<pre class='metadata'>
Title: CSSOM View Module Level 1
ED: https://drafts.csswg.org/cssom-view/
TR: https://www.w3.org/TR/cssom-view-1/
Previous Version: https://www.w3.org/TR/2016/WD-cssom-view-1-20160317/
Previous Version: https://www.w3.org/TR/2013/WD-cssom-view-20131217/
Previous Version: https://www.w3.org/TR/2011/WD-cssom-view-20110804/
Previous Version: https://www.w3.org/TR/2009/WD-cssom-view-20090804/
Previous Version: https://www.w3.org/TR/2008/WD-cssom-view-20080222/
Previous Version: https://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/
Group: CSSWG
Status: ED
Prepare for TR: no
Work Status: Revising
Shortname: cssom-view
Level: 1
Editor: Simon Fraser, Apple Inc http://www.apple.com/, simon.fraser@apple.com, w3cid 44066
Editor: Emilio Cobos Álvarez 106537, Mozilla https://mozilla.org, emilio@mozilla.com
Former Editor: Simon Pieters, Opera Software AS http://www.opera.com, simonp@opera.com
Former Editor: Glenn Adams, Cox Communications&#44; Inc. http://www.cox.com, glenn.adams@cos.com, http://www.w3.org/wiki/User:Gadams
Former Editor: Anne van Kesteren, Opera Software ASA http://www.opera.com, annevk@annevk.nl, https://annevankesteren.nl/
!Legacy issues list: <a href="https://www.w3.org/Bugs/Public/buglist.cgi?product=CSS&amp;component=CSSOM%20View&amp;resolution=---">Bugzilla</a>
Abstract: The APIs introduced by this specification provide authors with a way to inspect and manipulate the visual view of a document. This includes getting the position of element layout boxes, obtaining the width of the viewport through script, and also scrolling an element.
Ignored Vars: rect, point, quad
WPT Path Prefix: css/cssom-view/
WPT Display: open
Include Can I Use Panels: true
Can I Use URL: https://drafts.csswg.org/cssom-view-1/
Can I Use URL: https://www.w3.org/TR/cssom-view-1/
Ignore Can I Use URL Failure: https://drafts.csswg.org/cssom-view-1/
</pre>

<pre class='link-defaults'>
spec:css-ui-4; type:property; text:pointer-events
spec:css-viewport; type:dfn; text:effective zoom
spec:css2; type:dfn;
    text: canvas
    text: viewport
spec:dom; type:dfn; text:parent element
spec:html; type:dfn;
    text: inert
    text: the body element
    text: rules for parsing integers
    text: being rendered
spec:html; type:element; text:body
spec:css-overflow-3; type:property; text:scroll-behavior
spec:css-overflow-3; type:value; text:smooth
spec:css-overflow-3; type:value; text:auto
spec:css2; type:dfn; for:/; text:media
spec:css-scoping-1; type:dfn; text:shadow root
spec:dom; type:dfn; text:host
spec:dom; type:dfn; text:element
spec:dom; type:dfn; for:Attr; text:element
spec:css-borders-4; type:property; text:border-top-width
spec:css-borders-4; type:property; text:border-left-width
spec:cssom-view-1; type:dictionary; text:MouseEventInit
spec:cssom-view-1; type:dfn; for:MediaQueryList; text:media
spec:webdriver-bidi; type:dfn;
    text:WebDriver BiDi emulated available screen area
    text:WebDriver BiDi emulated total screen area
</pre>

<style>
main .atrisk::before {
    float: right;
    margin-top: -0.25em;
    padding: 0.5em 1em 0.5em 0;
    text-indent: -0.9em;
    border: 1px solid;
    content: '\25C0    Not yet widely implemented';
    white-space: pre;
    font-size: small;
    background-color: white;
    color: gray;
    text-align: center;
}
</style>

<script src=https://resources.whatwg.org/file-issue.js async data-file-issue-url="https://github.com/w3c/csswg-drafts/issues/new?title=%5Bcssom-view%5D%20"></script>

<style>
.selected-text-file-an-issue {
    position: fixed;
    bottom: 0;
    right: 0;
    background: rgba(255, 255, 255, 0.8);
    font-size: smaller;
    padding: 4px 10px;
    z-index: 1;
    text-decoration: underline;
}
@media (max-width: 767px) {
    .selected-text-file-an-issue { left: 0; right: auto; text-align: left; }
}
</style>

<h2 id=background>Background</h2>

Many of the features defined in this specification have been supported
by browsers for a long period of time. The goal of this specification is
to define these features in such a way that they can be implemented by all
browsers in an interoperable manner. The specification also defines a
some new features which allow for scroll customization.

<wpt title="Basic IDL tests">
idlharness.html
</wpt>

<h2 id=terminology>Terminology</h2>

Terminology used in this specification is from
DOM,
CSSOM and
HTML.
[[!DOM]]
[[!CSSOM]]
[[!HTML]]

An element <var>body</var> (which will be <a>the <code>body</code> element</a>) is
<dfn>potentially scrollable</dfn> if all of the following conditions are true:

* <var>body</var> has an associated [=CSS/box=].
* <var>body</var>'s <a>parent element</a>'s computed value of the 'overflow-x' or 'overflow-y' properties is neither ''overflow/visible'' nor ''overflow/clip''.
* <var>body</var>'s computed value of the 'overflow-x' or 'overflow-y' properties is neither ''overflow/visible'' nor ''overflow/clip''.

Note: A <{body}> element that is <a>potentially scrollable</a> might not have a <a>scrolling box</a>.
For instance, it could have a used value of 'overflow' being ''overflow/auto'' but not have its content overflowing its content area.

A <dfn export>scrolling box</dfn> of a <a>viewport</a> or element has two <dfn>overflow directions</dfn>, which are the <a>block-end</a> and <a>inline-end</a> directions for that viewport or element.
Note that the initial scroll position might not be aligned with the [=scrolling area origin=]
depending on the [=content-distribution properties=], see [[css-align-3#overflow-scroll-position]].

The term <dfn>scrolling area</dfn> refers to a box of a <a>viewport</a> or an element that has the following edges, depending on the
<a>viewport’s</a> or element's <a>scrolling box’s</a> <a>overflow directions</a>.

<table class="complex data">
 <thead>
  <tr>
   <th>If the <a>overflow directions</a> are&hellip;
   <th>For a <a>viewport</a>
   <th>For an element
 <tbody>
  <tr>
   <td>rightward and downward
   <td class=long>
    <dl>
     <dt>top edge
     <dd>The top edge of the <a>initial containing block</a>.
     <dt>right edge
     <dd>The right-most edge of the right edge of the <a>initial containing block</a> and the right
     <a>margin edge</a> of all of the <a>viewport’s</a> descendants' boxes.
     <dt>bottom edge
     <dd>The bottom-most edge of the bottom edge of the <a>initial containing block</a> and the
     bottom <a>margin edge</a> of all of the <a>viewport’s</a> descendants' boxes.
     <dt>left edge
     <dd>The left edge of the <a>initial containing block</a>.
    </dl>
   <td class=long>
    <dl>
     <dt>top edge
     <dd>The element's top <a>padding edge</a>.
     <dt>right edge
     <dd>The right-most edge of the element's right <a>padding edge</a> and the right <a>margin
     edge</a> of all of the element's descendants' boxes,
     excluding boxes that have an ancestor of the element as their containing block.
     <dt>bottom edge
     <dd>The bottom-most edge of the element's bottom <a>padding edge</a> and the bottom <a>margin
     edge</a> of all of the element's descendants'
     boxes, excluding boxes that have an ancestor of the element as their containing block.
     <dt>left edge
     <dd>The element's left <a>padding edge</a>.
    </dl>
  <tr>
   <td>leftward and downward
   <td class=long>
    <dl>
     <dt>top edge
     <dd>The top edge of the <a>initial containing block</a>.
     <dt>right edge
     <dd>The right edge of the <a>initial containing block</a>.
     <dt>bottom edge
     <dd>The bottom-most edge of the bottom edge of the <a>initial containing block</a> and the
     bottom <a>margin edge</a> of all of the <a>viewport’s</a> descendants' boxes.
     <dt>left edge
     <dd>The left-most edge of the left edge of the <a>initial containing block</a> and the left
     <a>margin edge</a> of all of the <a>viewport’s</a> descendants' boxes.
    </dl>
   <td class=long>
    <dl>
     <dt>top edge
     <dd>The element's top <a>padding edge</a>.
     <dt>right edge
     <dd>The element's right <a>padding edge</a>.
     <dt>bottom edge
     <dd>The bottom-most edge of the element's bottom <a>padding edge</a> and the bottom <a>margin
     edge</a> of all of the element's descendants' boxes, excluding boxes that have an ancestor of
     the element as their containing block.
     <dt>left edge
     <dd>The left-most edge of the element's left <a>padding edge</a> and the left <a>margin
     edge</a> of all of the element's descendants' boxes, excluding boxes that have an ancestor of
     the element as their containing block.
    </dl>
  <tr>
   <td>leftward and upward
   <td class=long>
    <dl>
     <dt>top edge
     <dd>The top-most edge of the top edge of the <a>initial containing block</a> and the top
     <a>margin edge</a> of all of the <a>viewport’s</a> descendants' boxes.
     <dt>right edge
     <dd>The right edge of the <a>initial containing block</a>.
     <dt>bottom edge
     <dd>The bottom edge of the <a>initial containing block</a>.
     <dt>left edge
     <dd>The left-most edge of the left edge of the <a>initial containing block</a> and the left
     <a>margin edge</a> of all of the <a>viewport’s</a> descendants' boxes.
    </dl>
   <td class=long>
    <dl>
     <dt>top edge
     <dd>The top-most edge of the element's top <a>padding edge</a> and the top <a>margin edge</a>
     of all of the element's descendants' boxes, excluding boxes that have an ancestor of the
     element as their containing block.
     <dt>right edge
     <dd>The element's right <a>padding edge</a>.
     <dt>bottom edge
     <dd>The element's bottom <a>padding edge</a>.
     <dt>left edge
     <dd>The left-most edge of the element's left <a>padding edge</a> and the left <a>margin
     edge</a> of all of the element's descendants' boxes, excluding boxes that have an ancestor of
     the element as their containing block.
    </dl>
  <tr>
   <td>rightward and upward
   <td class=long>
    <dl>
     <dt>top edge
     <dd>The top-most edge of the top edge of the <a>initial containing block</a> and the top
     <a>margin edge</a> of all of the <a>viewport’s</a> descendants' boxes.
     <dt>right edge
     <dd>The right-most edge of the right edge of the <a>initial containing block</a> and the right
     <a>margin edge</a> of all of the <a>viewport’s</a> descendants' boxes.
     <dt>bottom edge
     <dd>The bottom edge of the <a>initial containing block</a>.
     <dt>left edge
     <dd>The left edge of the <a>initial containing block</a>.
    </dl>
   <td class=long>
    <dl>
     <dt>top edge
     <dd>The top-most edge of the element's top <a>padding edge</a> and the top <a>margin edge</a>
     of all of the element's descendants' boxes, excluding boxes that have an ancestor of the
     element as their containing block.
     <dt>right edge
     <dd>The right-most edge of the element's right <a>padding edge</a> and the right <a>margin
     edge</a> of all of the element's descendants' boxes, excluding boxes that have an ancestor of
     the element as their containing block.
     <dt>bottom edge
     <dd>The element's bottom <a>padding edge</a>.
     <dt>left edge
     <dd>The element's left <a>padding edge</a>.
    </dl>
</table>

The <dfn lt="scrolling area origin">origin</dfn> of a <a>scrolling area</a> is
the origin of the <a>initial containing block</a> if the <a>scrolling area</a> is a <a>viewport</a>,
and otherwise the top left padding edge of the element when the element has its default scroll position.
The x-coordinate increases rightwards, and the y-coordinate increases downwards.

The <dfn>beginning edges</dfn> of a particular set of edges of a box or element are the following edges:

<dl class=switch>
 <dt>If the <a>overflow directions</a> are rightward and downward
 <dd>The top and left edges.
 <dt>If the <a>overflow directions</a> are leftward and downward
 <dd>The top and right edges.
 <dt>If the <a>overflow directions</a> are leftward and upward
 <dd>The bottom and right edges.
 <dt>If the <a>overflow directions</a> are rightward and upward
 <dd>The bottom and left edges.
</dl>

The <dfn>ending edges</dfn> of a particular set of edges of a box or element are the following edges:

<dl class=switch>
 <dt>If the <a>overflow directions</a> are rightward and downward
 <dd>The bottom and right edges.
 <dt>If the <a>overflow directions</a> are leftward and downward
 <dd>The bottom and left edges.
 <dt>If the <a>overflow directions</a> are leftward and upward
 <dd>The top and left edges.
 <dt>If the <a>overflow directions</a> are rightward and upward
 <dd>The top and right edges.
</dl>

The <dfn>visual viewport</dfn> is a kind of <a>viewport</a> whose <a>scrolling area</a> is another <a>viewport</a>,
called the <dfn export>layout viewport</dfn>.

In addition to scrolling, the <a>visual viewport</a> may also apply a scale transform to its <a>layout viewport</a>.
This transform is applied to the <a>canvas</a> of the <a>layout viewport</a> and does not affect its internal coordinate space.

Note: The scale transform of the visual viewport is often referred to as "pinch-zoom". Conceptually, this transform
changes the size of the CSS <a>reference pixel</a> but changes the size of the layout viewport proportionally so that it
does not cause reflow of the page's contents.

The magnitude of the scale transform is known as the <a>visual viewport</a>'s <dfn>scale factor</dfn>.

<style>
      @keyframes lvmove {
        0%, 10%, 20% { transform: translate(0, 100px); }
        30%, 50%, 70% { transform: translate(0, 150px); }
        80%,100% { transform: translate(0, 100px); }
      }
      @keyframes vvmove {
        0%, 10% { transform: translate(70px, 150px); }
        30%, 50% { transform: translate(70px, 250px); }
        80%, 90% { transform: translate(70px, 100px); }
        100% { transform: translate(70px, 150px); }
      }
      #lv {
        transform: translate(0, 100px);
        animation: lvmove linear 3s infinite;
      }
      #vv {
        transform: translate(20px, 150px);
        animation: vvmove linear 3s infinite;
      }
      .paused #lv {
        animation-play-state: paused;
      }
      .paused #vv {
        animation-play-state: paused;
      }
</style>
<div class="example paused" id="example-vvanimation">
  <p>
    This animation shows an example of a zoomed in visual viewport being "panned" around (for
    example, by a user performing a touch drag). The page is scaled so that the layout viewport
    is larger than the visual viewport.
  </p>
  <p>
    A scroll delta is applied to the visual viewport first. When the visual viewport is at its
    extent, scroll delta will be applied to the layout viewport. This behavior is implemented by
    the [=viewport/perform a scroll=] steps.
  </p>
  <svg width="300" height="400">
    <rect width="100%" height="100%" fill="white" stroke="grey" stroke-width="3"/>
    <text x="10" y="30" font-family="Sans" font-size="25" fill="grey">
      Document
    </text>
    <g id="lv">
      <rect y="2" x="2" width="296" height="200" stroke="blue" fill="none" stroke-width="4"/>
      <text x="10" y="20" font-family="Sans" font-size="15" fill="blue">
        Layout Viewport
      </text>
    </g>
    <g id="vv">
      <rect y="2" x="2" width="148" height="100" stroke="red" fill="none" stroke-width="4"/>
      <text x="10" y="60" font-family="Sans" font-size="15" fill="red">
        Visual Viewport
      </text>
    </g>
  </svg>
  <br>
  <button id="vvanimationBtn">Toggle Animation</button>
  <script>
    document.getElementById('vvanimationBtn').onclick = () => {
      document.getElementById('example-vvanimation').classList.toggle('paused');
    };
  </script>
</div>

The {{VisualViewport}} object has an <dfn for=visualviewport>associated document</dfn>, which is a {{Document}} object.
It is the <a for="/">associated document</a> of the owner {{Window}} of {{VisualViewport}}. The <a>layout viewport</a>
is the owner {{Window}}'s <a>viewport</a>.

For the purpose of the requirements in this specification,
elements that have a computed value of the 'display' property
that is ''table-column'' or ''table-column-group''
must be considered to have an associated [=CSS/box=]
(the column or column group, respectively).

The term <dfn>SVG layout box</dfn> refers to a [=CSS/box=] generated by an SVG element
which does not correspond to a CSS-defined 'display' type.
(Such as the [=CSS/box=] generated by a <{rect}> element.)

The term <dfn noexport>transforms</dfn> refers to SVG transforms and CSS transforms. [[!SVG11]] [[!CSS-TRANSFORMS-1]]

When a method or an attribute is said to call another method or attribute, the user agent must invoke its internal API for that attribute or method so that
e.g. the author can't change the behavior by overriding attributes or methods with custom properties or functions in ECMAScript.

Unless otherwise stated, all string comparisons use [=string/is=].


<h3 id=css-pixels>CSS pixels</h3>

All coordinates and dimensions for the APIs defined in this
specification are in <a lt=px value>CSS pixels</a>, unless otherwise specified. [[!CSS-VALUES]]

Note: This does not apply to e.g. {{matchMedia()}} as the units are explicitly given there.


<h3 id=zooming>Zooming</h3>

There are two kinds of zoom, <dfn>page zoom</dfn> which affects the size of the initial viewport<!-- XXX ref -->, and the visual viewport <a>scale factor</a> which acts like
a magnifying glass and does not affect the initial viewport<!-- XXX ref --> or actual viewport<!-- XXX ref -->. [[!CSS-DEVICE-ADAPT]]

Note: The "scale factor" is often referred to as "pinch-zoom"; however, it can be affected through means other than
pinch-zooming. e.g. The user agent may zooms in on a focused input element to make it legible.


<h3 id=web-exposed-screen-information>Web-exposed screen information</h3>

User agents may choose to hide information about the screen of the output device, in order to
protect the user's privacy. In order to do so in a consistent manner across APIs, this specification
defines the following terms, each having a width and a height, the origin being the top left
corner, and the x- and y-coordinates increase rightwards and downwards, respectively.

The <dfn export>Web-exposed screen area</dfn> must return the result of the following algorithm:

1. Let <var>target</var> be [=this=]'s [=relevant global object=]'s [=Window/browsing context=].
1. Let |emulated screen area| be the <a>WebDriver BiDi emulated total screen area</a> of <var>target</var>.
1. If |emulated screen area| is not null, return |emulated screen area|.
1. Otherwise, return one of the following:
    * The area of the output device, in <a lt=px value>CSS pixels</a>.
    * The area of the <a>viewport</a>, in <a lt=px value>CSS pixels</a>.

The <dfn export>Web-exposed available screen area</dfn> must return the result of the following algorithm:

1. Let <var>target</var> be [=this=]'s [=relevant global object=]'s [=Window/browsing context=].
1. Let |emulated screen area| be the <a>WebDriver BiDi emulated available screen area</a> for <var>target</var>.
1. If |emulated screen area| is not null, return |emulated screen area|.
1. Otherwise, return one of the following:
    * The available area of the rendering surface of the output device, in <a lt=px value>CSS pixels</a>.
    * The area of the output device, in <a lt=px value>CSS pixels</a>.
    * The area of the <a>viewport</a>, in <a lt=px value>CSS pixels</a>.


<h2 id=common-infrastructure>Common Infrastructure</h2>

This specification depends on the WHATWG Infra standard. [[!INFRA]]


<h3 id=scrolling>Scrolling</h3>

<div algorithm="perform a scroll of a box">

When a user agent is to <dfn export>perform a scroll</dfn> of a <a>scrolling box</a> <var>box</var>,
to a given position <var>position</var>,
an associated element or [=pseudo-element=] <var>element</var> and optionally a scroll behavior <var>behavior</var>
(which is "<code>auto</code>" if omitted),
the following steps must be run:

1. <a lt="smooth scroll aborted">Abort</a> any ongoing <a>smooth scroll</a> for <var>box</var>.
1. Resolve all pending scroll {{Promise}}s whose scroll container is <var>box</var>.
1. Let <var>scrollPromise</var> be a new {{Promise}}.
1. Return <var>scrollPromise</var>, and run the remaining steps <a>in parallel</a>.
1. If the user agent honors the 'scroll-behavior' property and one of the following is true:
    <ul>
      <li><var>behavior</var> is "<code>auto</code>" and <var>element</var> is not null and its computed value of the
      'scroll-behavior' property is ''scroll-behavior/smooth'', or
      <li><var>behavior</var> is <code>smooth</code>
    </ul>
    then perform a <a>smooth scroll</a> of <var>box</var> to <var>position</var>;
    otherwise, perform an <a>instant scroll</a> of <var>box</var> to <var>position</var>.
1. Wait until either the position has finished updating, or <var>scrollPromise</var> has been resolved.
1. If <var>scrollPromise</var> is still in the pending state:
    1. If the scroll position changed as a result of this call, emit the <a event>scrollend</a> event.
    1. Resolve <var>scrollPromise</var>.

  Note: <code>behavior: "instant"</code> always performs an <a>instant scroll</a> by this algorithm.

  Note: If the scroll position did not change as a result of the user interaction or programmatic invocation, where no translations were applied as a result, then no <a event>scrollend</a> event fires because no scrolling occurred.
</div>

<div algorithm="perform a scroll of a viewport">

When a user agent is to <dfn for="viewport" export>perform a scroll</dfn> of a <a>viewport</a> to a given position <var>position</var> and optionally a scroll behavior <var>behavior</var>
(which is "<code>auto</code>" if omitted) it must perform a coordinated viewport scroll by following these steps:

1. Let <var>doc</var> be the <a>viewport's</a> associated {{Document}}.
1. Let <var>vv</var> be the {{VisualViewport}} whose <a for=visualviewport>associated document</a> is <var>doc</var>.
1. Let <var>maxX</var> be the difference between <a>viewport</a>'s <a>scrolling box</a>'s width and the value of <var>vv</var>'s <a attribute
    for=VisualViewport lt=width>width</a> attribute.
1. Let <var>maxY</var> be the difference between <a>viewport</a>'s <a>scrolling box</a>'s height and the value of <var>vv</var>'s <a attribute
    for=VisualViewport lt=height>height</a> attribute.
1. Let <var>dx</var> be the horizontal component of <var>position</var> - the value <var>vv</var>'s <a attribute for=VisualViewport lt=pageLeft>pageLeft</a> attribute
1. Let <var>dy</var> be the vertical component of <var>position</var> - the value of <var>vv</var>'s <a attribute for=VisualViewport lt=pageTop>pageTop</a> attribute
1. Let <var>visual x</var> be the value of <var>vv</var>'s <a attribute for=VisualViewport lt=offsetLeft>offsetLeft</a> attribute.
1. Let <var>visual y</var> be the value of <var>vv</var>'s <a attribute for=VisualViewport lt=offsetTop>offsetTop</a> attribute.
1. Let <var>visual dx</var> be min(<var>maxX</var>, max(0, <var>visual x</var> + <var>dx</var>)) - <var>visual x</var>.
1. Let <var>visual dy</var> be min(<var>maxY</var>, max(0, <var>visual y</var> + <var>dy</var>)) - <var>visual y</var>.
1. Let <var>layout dx</var> be <var>dx</var> - <var>visual dx</var>
1. Let <var>layout dy</var> be <var>dy</var> - <var>visual dy</var>
1. Let <var>element</var> be <var>doc</var>'s root element if there is one, null otherwise.
1. <a for="/">Perform a scroll</a> of the <a>viewport</a>'s <a>scrolling box</a> to its current scroll position + (<var>layout dx</var>, <var>layout dy</var>) with <var>element</var> as the
    associated element, and <var>behavior</var> as the scroll behavior.
    Let <var>scrollPromise1</var> be the {{Promise}} returned from this step.
1. <a for="/">Perform a scroll</a> of <var>vv</var>'s <a>scrolling box</a> to its current scroll position + (<var>visual dx</var>, <var>visual dy</var>) with <var>element</var> as the associated
    element, and <var>behavior</var> as the scroll behavior.
    Let <var>scrollPromise2</var> be the {{Promise}} returned from this step.
1. Let <var>scrollPromise</var> be a new {{Promise}}.
1. Return <var>scrollPromise</var>, and run the remaining steps <a>in parallel</a>.
1. Resolve <var>scrollPromise</var> when both <var>scrollPromise1</var> and <var>scrollPromise2</var> have settled.

Note: Conceptually, the visual viewport is scrolled until it "bumps up" against the layout viewport
edge and then "pushes" the layout viewport by applying the scroll delta to the layout viewport.
However, the scrolls in the steps above are computed ahead of time and applied in the opposite order
so that the layout viewport is scrolled before the visual viewport. This is done for historical
reasons to ensure consistent scroll event ordering. See the <a href="#example-vvanimation">example
above</a> for a visual depiction.

</div>

<div class='example'>
    The user pinch-zooms into the document and ticks their mouse wheel, requesting the user agent scroll the document down by 50px. Because the document
    is pinch-zoomed in, the visual viewport has 20px of room to scroll. The user agent distributes the scroll by scrolling the visual viewport down by
    20px and the layout viewport by 30px.
</div>

<div class='example'>
    The user is viewing a document in a mobile user agent. The document focuses an offscreen text input element, showing a virtual keyboard which shrinks
    the visual viewport. The user agent must now bring the element into view in the visual viewport. The user agent scrolls the layout viewport so that
    the element is visible within it, then the visual viewport so that the element is visible to the user.
</div>

Scroll is <dfn lt="scroll completed">completed</dfn> when the scroll position has no more pending updates or translations and the user has completed their gesture. Scroll position updates include smooth or instant mouse wheel scrolling, keyboard scrolling, scroll-snap events, or other APIs and gestures which cause the scroll position to update and possibly interpolate. User gestures like touch panning or trackpad scrolling aren't complete until pointers or keys have released.

When a user agent is to perform a <dfn export id=concept-smooth-scroll>smooth scroll</dfn> of a <a>scrolling box</a> <var>box</var> to <var>position</var>,
it must update the scroll position of <var>box</var> in a user-agent-defined fashion over a user-agent-defined amount of time. When the scroll is
<dfn export lt="smooth scroll completed">completed</dfn>, the scroll position of <var>box</var> must be <var>position</var>. The scroll can also
be <dfn export lt="smooth scroll aborted">aborted</dfn>, either by an algorithm or by the user. <!--fingerprint-->

When a user agent is to perform an <dfn id=concept-instant-scroll>instant scroll</dfn> of a <a>scrolling box</a> <var>box</var> to
<var>position</var>, it must update the scroll position of <var>box</var> to <var>position</var>.

To <dfn export>scroll to the beginning of the document</dfn> for a document <var>document</var>, follow these steps:

<ol>
 <li>Let <var>viewport</var> be the <a>viewport</a> that is associated with <var>document</var>. <!-- This assumes that there is a viewport, since
 it is only invoked when navigating -->
 <li>Let <var>position</var> be the scroll position <var>viewport</var> would have by aligning the <a>beginning edges</a> of the
 <a>scrolling area</a> with the <a>beginning edges</a> of <var>viewport</var>.
 <li>If <var>position</var> is the same as <var>viewport</var>'s current scroll position, and <var>viewport</var> does not have an ongoing
 <a>smooth scroll</a>, abort these steps.
 <li><a for="viewport">Perform a scroll</a> of <var>viewport</var> to <var>position</var>,
 and <var>document</var>'s [=root element=] as the associated element, if there is one, or null otherwise.
</ol>

Note: This algorithm is used when navigating to the <code>#top</code> fragment identifier, as defined in HTML. [[!HTML]]

<wpt>
    interrupt-hidden-smooth-scroll.html
    long_scroll_composited.html
    scroll-back-to-initial-position.html
    scrolling-no-browsing-context.html
    scrolling-quirks-vs-nonquirks.html
    smooth-scroll-in-load-event.html
    smooth-scroll-nonstop.html
</wpt>

<h3 id=webidl-values>WebIDL values</h3>

When asked to <dfn>normalize non-finite values</dfn> for a value <var>x</var>,
if <var>x</var> is one of the three special floating point literal values
(<code>Infinity</code>, <code>-Infinity</code> or <code>NaN</code>),
then <var>x</var> must be changed to the value <code>0</code>. [[!WEBIDL]]


<h2 id=extensions-to-the-window-interface>Extensions to the {{Window}} Interface</h2>

<pre class=idl>
enum ScrollBehavior { "auto", "instant", "smooth" };

dictionary ScrollOptions {
    ScrollBehavior behavior = "auto";
};
dictionary ScrollToOptions : ScrollOptions {
    unrestricted double left;
    unrestricted double top;
};

partial interface Window {
    [NewObject] MediaQueryList matchMedia(CSSOMString query);
    [SameObject, Replaceable] readonly attribute Screen screen;
    [SameObject, Replaceable] readonly attribute VisualViewport? visualViewport;

    // browsing context
    undefined moveTo(long x, long y);
    undefined moveBy(long x, long y);
    undefined resizeTo(long width, long height);
    undefined resizeBy(long x, long y);

    // viewport
    [Replaceable] readonly attribute long innerWidth;
    [Replaceable] readonly attribute long innerHeight;

    // viewport scrolling
    [Replaceable] readonly attribute double scrollX;
    [Replaceable] readonly attribute double pageXOffset;
    [Replaceable] readonly attribute double scrollY;
    [Replaceable] readonly attribute double pageYOffset;
    Promise&lt;undefined> scroll(optional ScrollToOptions options = {});
    Promise&lt;undefined> scroll(unrestricted double x, unrestricted double y);
    Promise&lt;undefined> scrollTo(optional ScrollToOptions options = {});
    Promise&lt;undefined> scrollTo(unrestricted double x, unrestricted double y);
    Promise&lt;undefined> scrollBy(optional ScrollToOptions options = {});
    Promise&lt;undefined> scrollBy(unrestricted double x, unrestricted double y);

    // client
    [Replaceable] readonly attribute long screenX;
    [Replaceable] readonly attribute long screenLeft;
    [Replaceable] readonly attribute long screenY;
    [Replaceable] readonly attribute long screenTop;
    [Replaceable] readonly attribute long outerWidth;
    [Replaceable] readonly attribute long outerHeight;
    [Replaceable] readonly attribute double devicePixelRatio;
};
</pre>

Issue: Should the scroll methods above return a result object and if so what information should they provide? #12495

When the <dfn method for=Window caniuse=matchmedia>matchMedia(<var>query</var>)</dfn> method is invoked these steps must be run:
<ol>
 <li>Let <var>parsed media query list</var> be the result of
 <a lt='parse a media query list'>parsing</a>
 <var>query</var>.
 <li>Return a new {{MediaQueryList}} object,
 with [=this=]'s
 <a for="/">associated <code>Document</code></a>
 as the <a for=MediaQueryList>document</a>,
 with <var>parsed media query list</var> as its associated [=MediaQueryList/media query list=].
</ol>

<wpt>
    matchMedia-display-none-iframe.html
    matchMedia.html
</wpt>

The <dfn attribute for=Window>screen</dfn> attribute must return the {{Screen}} object
associated with the {{Window}} object.

Note: Accessing {{Window/screen}} through a {{WindowProxy}} object might yield different
results when the {{Document}} is navigated.

If the <a for="/">associated document</a> is <a>fully active</a>, the <dfn attribute for=Window>visualViewport</dfn>
attribute must return the {{VisualViewport}} object associated with the {{Window}} object's <a for="/">associated
document</a>. Otherwise, it must return null.

Note: the VisualViewport object is only returned and useful for a window whose Document is currently being presented. If
a reference is retained to a VisualViewport whose associated Document is not being currently presented, the values in
that VisualViewport must not reveal any information about the browsing context.

<wpt>
    window-screen-height-immutable.html
    window-screen-height.html
    window-screen-width-immutable.html
    window-screen-width.html
</wpt>

The <dfn method for=Window>moveTo(<var>x</var>, <var>y</var>)</dfn> method must follow these steps:

1. Optionally, return.
1. Let <var>target</var> be [=this=]'s [=relevant global object=]'s [=Window/browsing context=].
1. If |target| is not an [=auxiliary browsing context=] that was created by a script (as opposed to by an action of the user), then return.
1. Optionally, clamp <var>x</var> and <var>y</var> in a user-agent-defined manner so that the window does not move outside the available space.
1. Move <var>target</var>’s window such that the window’s top left corner is at coordinates (<var>x</var>, <var>y</var>) relative to the top left corner of the output device, measured in <a lt=px value>CSS pixels</a> of <var>target</var>. The positive axes are rightward and downward.

The <dfn method for=Window>moveBy(<var>x</var>, <var>y</var>)</dfn> method must follow these steps:

1. Optionally, return.
1. Let <var>target</var> be [=this=]'s [=relevant global object=]'s [=Window/browsing context=].
1. If |target| is not an [=auxiliary browsing context=] that was created by a script (as opposed to by an action of the user), then return.
1. Optionally, clamp <var>x</var> and <var>y</var> in a user-agent-defined manner so that the window does not move outside the available space.
1. Move <var>target</var>'s window <var>x</var> <a lt=px value>CSS pixels</a> of <var>target</var> rightward and <var>y</var> <a lt=px value>CSS pixels</a> of <var>target</var> downward.


The <dfn method for=Window>resizeTo(<var>width</var>, <var>height</var>)</dfn> method must follow these steps:

1. Optionally, return.
1. Let <var>target</var> be [=this=]'s [=relevant global object=]'s [=Window/browsing context=].
1. If |target| is not an [=auxiliary browsing context=] that was created by a script (as opposed to by an action of the user), then return.
1. Optionally, clamp <var>width</var> and <var>height</var> in a user-agent-defined manner so that the window does not get too small or bigger than the available space.
1. Resize <var>target</var>'s window by moving its right and bottom edges such that the distance between the left and right edges of the viewport are <var>width</var> <a lt=px value>CSS pixels</a> of <var>target</var> and the distance between the top and bottom edges of the viewport are <var>height</var> <a lt=px value>CSS pixels</a> of <var>target</var>.
1. Optionally, move <var>target</var>'s window in a user-agent-defined manner so that it does not grow outside the available space.

<wpt>
    resizeTo-negative.html
</wpt>

The <dfn method for=Window>resizeBy(<var>x</var>, <var>y</var>)</dfn> method must follow these steps:

1. Optionally, return.
1. Let <var>target</var> be [=this=]'s [=relevant global object=]'s [=Window/browsing context=].
1. If |target| is not an [=auxiliary browsing context=] that was created by a script (as opposed to by an action of the user), then return.
1. Optionally, clamp <var>x</var> and <var>y</var> in a user-agent-defined manner so that the window does not get too small or bigger than the available space.
1. Resize <var>target</var>'s window by moving its right edge <var>x</var> <a lt=px value>CSS pixels</a> of <var>target</var> rightward and its bottom edge <var>y</var> <a lt=px value>CSS pixels</a> of <var>target</var> downward.
1. Optionally, move <var>target</var>'s window in a user-agent-defined manner so that it does not grow outside the available space.

The <dfn attribute for=Window>innerWidth</dfn> attribute must return the <a>viewport</a> width including the size of a rendered
scroll bar (if any), or zero if there is no <a>viewport</a>. <!--fingerprint-->

<div class='example'>
    The following snippet shows how to obtain the width of the viewport:

    <pre>var viewportWidth = innerWidth</pre>
</div>

The  <dfn attribute for=Window>innerHeight</dfn> attribute must return the <a>viewport</a> height including the size of a rendered
scroll bar (if any), or zero if there is no <a>viewport</a>. <!--fingerprint-->

The <dfn attribute for=Window>scrollX</dfn> attribute must return the x-coordinate,
relative to the <a>initial containing block</a> origin,
of the left of the <a>viewport</a>,
or zero if there is no <a>viewport</a>. <!--fingerprint-->

The <dfn attribute for=Window>pageXOffset</dfn> attribute must return the value returned by the {{scrollX}} attribute.

The <dfn attribute for=Window>scrollY</dfn> attribute must return the y-coordinate,
relative to the <a>initial containing block</a> origin,
of the top of the <a>viewport</a>,
or zero if there is no <a>viewport</a>. <!--fingerprint-->

The <dfn attribute for=Window>pageYOffset</dfn> attribute must return the value returned by the {{scrollY}} attribute.

When the <dfn method for=Window lt="scroll(options)|scroll(x, y)">scroll()</dfn> method is invoked these
steps must be run:

1. If invoked with one argument, follow these substeps:
    1. Let <var>options</var> be the argument.
    1. Let <var>x</var> be the value of the {{ScrollToOptions/left}} dictionary member of <var>options</var>, if present,
        or the <a>viewport’s</a> current scroll position on the x axis otherwise.
    1. Let <var>y</var> be the value of the {{ScrollToOptions/top}} dictionary member of <var>options</var>, if present,
        or the <a>viewport’s</a> current scroll position on the y axis otherwise.
1. If invoked with two arguments, follow these substeps:
    1. Let <var>options</var> be null <a lt="converted to an IDL value">converted</a> to a {{ScrollToOptions}} dictionary. [[!WEBIDL]]
    1. Let <var>x</var> and <var>y</var> be the arguments, respectively.
1. <a>Normalize non-finite values</a> for <var>x</var> and <var>y</var>.
1. If there is no <a>viewport</a>, return a resolved {{Promise}} and abort the remaining steps.
1. Let <var>viewport width</var> be the width of the <a>viewport</a> excluding the width of the scroll bar, if any.
1. Let <var>viewport height</var> be the height of the <a>viewport</a> excluding the height of the scroll bar, if any.
1.
    <dl class=switch>
        <dt>If the <a>viewport</a> has rightward <a>overflow direction</a>
        <dd>Let <var>x</var> be max(0, min(<var>x</var>, <a>viewport</a> <a>scrolling area</a> width - <var>viewport width</var>)).

        <dt>If the <a>viewport</a> has leftward <a>overflow direction</a>
        <dd>Let <var>x</var> be min(0, max(<var>x</var>, <var>viewport width</var> - <a>viewport</a> <a>scrolling area</a> width)).
    </dl>
1.
    <dl class=switch>
        <dt>If the <a>viewport</a> has downward <a>overflow direction</a>
        <dd>Let <var>y</var> be max(0, min(<var>y</var>, <a>viewport</a> <a>scrolling area</a> height - <var>viewport height</var>)).

        <dt>If the <a>viewport</a> has upward <a>overflow direction</a>
        <dd>Let <var>y</var> be min(0, max(<var>y</var>, <var>viewport height</var> - <a>viewport</a> <a>scrolling area</a> height)).
    </dl>
1. Let <var>position</var> be the scroll position the <a>viewport</a> would have
    by aligning the x-coordinate <var>x</var> of the <a>viewport</a> <a>scrolling area</a>
    with the left of the <a>viewport</a>
    and aligning the y-coordinate <var>y</var> of the <a>viewport</a> <a>scrolling area</a>
    with the top of the <a>viewport</a>.
1. If <var>position</var> is the same as the <a>viewport’s</a> current scroll position,
    and the <a>viewport</a> does not have an ongoing <a>smooth scroll</a>, return a resolved {{Promise}} and abort the remaining steps.
1. Let <var>document</var> be the <a>viewport’s</a> associated {{Document}}.
1. <a for="viewport">Perform a scroll</a> of the <a>viewport</a> to <var>position</var>,
    <var>document</var>'s [=root element=] as the associated element, if there is one, or null otherwise,
    and the scroll behavior being the value of the {{ScrollOptions/behavior}} dictionary member of <var>options</var>.
    Let <var>scrollPromise</var> be the {{Promise}} returned from this step.
1. Return <var>scrollPromise</var>.

    Issue: User agents do not agree whether this uses the (coordinated) <a>viewport</a> <a for="viewport">perform a scroll</a> or the
    <a>scrolling box</a> <a for="/">perform a scroll</a> on the layout viewport's scrolling box.

<wpt>
    add-background-attachment-fixed-during-smooth-scroll.html
    HTMLBody-ScrollArea_quirksmode.html
    window-scroll-arguments.html
</wpt>

When the <dfn method for=Window lt="scrollTo(options)|scrollTo(x, y)">scrollTo()</dfn> method is invoked, the
user agent must act as if the {{Window/scroll()}} method was invoked with the same arguments.

<wpt>
    background-change-during-smooth-scroll.html
    scrollTo-zoom.html
</wpt>

When the <dfn method for=Window lt="scrollBy(options)|scrollBy(x, y)">scrollBy()</dfn> method is invoked, the
user agent must run these steps:

1. If invoked with two arguments, follow these substeps:
    1. Let <var>options</var> be null <a lt="converted to an IDL value">converted</a> to a {{ScrollToOptions}} dictionary. [[!WEBIDL]]
    1. Let <var>x</var> and <var>y</var> be the arguments, respectively.
    1. Let the {{ScrollToOptions/left}} dictionary member of <var>options</var> have the value <var>x</var>.
    1. Let the {{ScrollToOptions/top}} dictionary member of <var>options</var> have the value <var>y</var>.
1. <a>Normalize non-finite values</a> for the {{ScrollToOptions/left}} and {{ScrollToOptions/top}} dictionary members of <var>options</var>.
1. Add the value of {{scrollX}} to the {{ScrollToOptions/left}} dictionary member.
1. Add the value of {{scrollY}} to the {{ScrollToOptions/top}} dictionary member.
1. Return the {{Promise}} returned from {{Window/scroll()}} after the method is invoked with <var>options</var> as the only argument.

The <dfn attribute for=Window>screenX</dfn> and <dfn attribute for=Window>screenLeft</dfn> attributes must return the x-coordinate,
relative to the origin of the <a>Web-exposed screen area</a>, of the left of
the client window as number of <a lt=px value>CSS pixels</a>, or zero if there is no such
thing. <!--fingerprint-->

<wpt>
    screenLeftTop.html
</wpt>

The <dfn attribute for=Window>screenY</dfn> and <dfn attribute for=Window>screenTop</dfn> attributes must return the y-coordinate,
relative to the origin of the screen of the <a>Web-exposed screen area</a>, of the top of
the client window as number of <a lt=px value>CSS pixels</a>, or zero if there is no such
thing. <!--fingerprint-->

The <dfn attribute for=Window>outerWidth</dfn> attribute must return the width of the
client window. If there is no client window this
attribute must return zero. <!--fingerprint-->

The <dfn attribute for=Window>outerHeight</dfn> attribute must return the height of the
client window. If there is no client window this
attribute must return zero. <!--fingerprint-->

The <dfn attribute for=Window caniuse=devicepixelratio>devicePixelRatio</dfn> attribute must return the result of the following <dfn export>determine the device pixel ratio</dfn> algorithm:

1. If there is no output device, return 1 and abort these steps.
1. Let <var>CSS pixel size</var> be the size of a <a lt=px value>CSS pixel</a> at the current <a>page zoom</a> and using a <a>scale factor</a> of 1.0.
1. Let <var>device pixel size</var> be the vertical size of a device pixel of the output device.
1. Return the result of dividing <var>CSS pixel size</var> by <var>device pixel size</var>.


<h3 id=the-features-argument-to-the-open()-method>The <var ignore>features</var> argument to the {{Window/open()}} method</h3>

HTML defines the {{Window/open()}} method. This section defines behavior for position and size given
in the <var ignore>features</var> argument. [[!HTML]]

To <dfn export>set up browsing context features</dfn> for a browsing context <var>target</var> given a
<a>map</a> <var>tokenizedFeatures</var>:

1. Let <var>x</var> be null.
1. Let <var>y</var> be null.
1. Let <var>width</var> be null.
1. Let <var>height</var> be null.
1. If <var>tokenizedFeatures</var>["<a for="supported open() feature name">left</a>"]
    <a for=map>exists</a>:
    1. Set <var>x</var> to the result of invoking the <a>rules for parsing integers</a> on
        <var>tokenizedFeatures</var>["<a for="supported open() feature name">left</a>"].
    1. If <var>x</var> is an error, set <var>x</var> to 0.
    1. Optionally, clamp <var>x</var> in a user-agent-defined manner so that the window does not
        move outside the <a>Web-exposed available screen area</a>.
    1. Optionally, move <var>target</var>'s window such that the window's left edge is at the
        horizontal coordinate <var>x</var> relative to the left edge of the <a>Web-exposed screen
        area</a>, measured in <a lt=px value>CSS pixels</a> of <var>target</var>. The positive axis is rightward.
1. If <var>tokenizedFeatures</var>["<a for="supported open() feature name">top</a>"]
    <a for=map>exists</a>:
    1. Set <var>y</var> to the result of invoking the <a>rules for parsing integers</a> on
        <var>tokenizedFeatures</var>["<a for="supported open() feature name">top</a>"].
    1. If <var>y</var> is an error, set <var>y</var> to 0.
    1. Optionally, clamp <var>y</var> in a user-agent-defined manner so that the window does not
        move outside the <a>Web-exposed available screen area</a>.
    1. Optionally, move <var>target</var>'s window such that the window's top edge is at the
        vertical coordinate <var>y</var> relative to the top edge of the <a>Web-exposed screen
        area</a>, measured in <a lt=px value>CSS pixels</a> of <var>target</var>. The positive axis is downward.
1. If <var>tokenizedFeatures</var>["<a for="supported open() feature name">width</a>"]
    <a for=map>exists</a>:
    1. Set <var>width</var> to the result of invoking the <a>rules for parsing integers</a> on
        <var>tokenizedFeatures</var>["<a for="supported open() feature name">width</a>"].
    1. If <var>width</var> is an error, set <var>width</var> to 0.
    1. If <var>width</var> is not 0:
        1. Optionally, clamp <var>width</var> in a user-agent-defined manner so that the window does
            not get too small or bigger than the <a>Web-exposed available screen area</a>.
        1. Optionally, size <var>target</var>'s window by moving its right edge such that the
            distance between the left and right edges of the viewport are <var>width</var>
            <a lt=px value>CSS pixels</a> of <var>target</var>.
        1. Optionally, move <var>target</var>'s window in a user-agent-defined manner so that it
            does not grow outside the <a>Web-exposed available screen area</a>.
1. If <var>tokenizedFeatures</var>["<a for="supported open() feature name">height</a>"]
    <a for=map>exists</a>:
    1. Set <var>height</var> to the result of invoking the <a>rules for parsing integers</a> on
        <var>tokenizedFeatures</var>["<a for="supported open() feature name">height</a>"].
    1. If <var>height</var> is an error, set <var>height</var> to 0.
    1. If <var>height</var> is not 0:
        1. Optionally, clamp <var>height</var> in a user-agent-defined manner so that the window
            does not get too small or bigger than the <a>Web-exposed available screen area</a>.
        1. Optionally, size <var>target</var>'s window by moving its bottom edge such that the
            distance between the top and bottom edges of the viewport are <var>height</var>
            <a lt=px value>CSS pixels</a> of <var>target</var>.
        1. Optionally, move <var>target</var>'s window in a user-agent-defined manner so that it
            does not grow outside the <a>Web-exposed available screen area</a>.

A <dfn export>supported <code>open()</code> feature name</dfn> is one of the following:

<dl dfn-for="supported open() feature name" export>
    <dt><dfn>width</dfn>
    <dd>The width of the viewport.

    <dt><dfn>height</dfn>
    <dd>The height of the viewport.

    <dt><dfn>left</dfn>
    <dd>The left position of the window.

    <dt><dfn>top</dfn>
    <dd>The top position of the window.
</dl>


<h3 id=the-mediaquerylist-interface>The {{MediaQueryList}} Interface</h3>

This section integrates with the <a for=/>event loop</a> defined in HTML. [[!HTML]]

A {{MediaQueryList}} object has an associated <dfn for=MediaQueryList>media query list</dfn>
and an associated <dfn for=MediaQueryList>document</dfn> set on creation.

A {{MediaQueryList}} object has an associated <dfn for=MediaQueryList>media</dfn> which is the
<a lt='serialize a media query list'>serialized</a> form of the associated [=MediaQueryList/media query list=].

A {{MediaQueryList}} object has an associated <dfn for=MediaQueryList>matches state</dfn> which is
true if the associated [=MediaQueryList/media query list=] matches the state of the <a for=MediaQueryList>document</a>, and false otherwise.

<!--XXX update the matches state when flushing layout (offsetWidth et al), without firing a change event. -->

When asked to <dfn export>evaluate media queries and report changes</dfn> for a {{Document}} <var>doc</var>, run these steps:

<ol>

 <li>

  For each {{MediaQueryList}} object <var>target</var> that has <var>doc</var> as its <a for=MediaQueryList>document</a>,
  in the order they were created, oldest first, run these substeps:

  <ol>

   <li>If <var>target</var>'s <a>matches state</a> has changed since the last time these steps were run,
   <a>fire an event</a> named <a event>change</a> at <var>target</var>
   using {{MediaQueryListEvent}},
   with its {{Event/isTrusted}} attribute initialized to true,
   its {{MediaQueryList/media}} attribute initialized to <var>target</var>'s <a>media</a>,
   and its {{MediaQueryListEvent/matches}} attribute initialized to <var>target</var>'s <a>matches state</a>. <!--fingerprint-->

  </ol>

</ol>

<div class='example'>
    A simple piece of code that detects changes in the orientation of the viewport can be written as follows:

    <pre highlight=javascript>
    function handleOrientationChange(event) {
        if(event.matches) // landscape
            &hellip;
        else
            &hellip;
    }
    var mql = matchMedia("(orientation:landscape)");
    mql.onchange = handleOrientationChange;
    </pre>
</div>

<pre class=idl>
[Exposed=Window]
interface MediaQueryList : EventTarget {
  readonly attribute CSSOMString media;
  readonly attribute boolean matches;
  undefined addListener(EventListener? callback);
  undefined removeListener(EventListener? callback);
           attribute EventHandler onchange;
};
</pre>

The <dfn attribute for=MediaQueryList>media</dfn> attribute must return
the associated <a>media</a>.

The <dfn attribute for=MediaQueryList>matches</dfn> attribute must return
the associated <a>matches state</a>. <!--fingerprint-->

The <dfn method for=MediaQueryList>addListener(<var>callback</var>)</dfn> method,
when invoked, must run these steps:

1. <a spec=dom>Add an event listener</a> with [=this=]
    and an <a spec=dom>event listener</a> whose
    <a spec=dom for="event listener">type</a> is <code>change</code>,
    and <a spec=dom for="event listener">callback</a> is |callback|.

The <dfn method for=MediaQueryList>removeListener(<var>callback</var>)</dfn> method,
when invoked, must run these steps:

1. If [=this=]’s <a spec=dom for=EventTarget>event listener list</a>
    <a for=list>contains</a> an <a>event listener</a> whose
    <a spec=dom for="event listener">type</a> is <code>change</code>,
    <a spec=dom for="event listener">callback</a> is |callback|,
    and <a spec=dom for="event listener">capture</a> is false,
    then <a spec=dom>remove an event listener</a> with
    [=this=] and that <a spec=dom>event listener</a>.

Note: This specification initially had a custom callback mechanism with {{addListener()}} and
{{removeListener()}}, and the callback was invoked with the associated media query list as argument.
Now the normal event mechanism is used instead.
For backwards compatibility, the {{addListener()}} and {{removeListener()}} methods
are basically aliases for {{addEventListener()}} and {{removeEventListener()}}, respectively,
and the <code>change</code> event masquerades as a {{MediaQueryList}}.

The following are the <a>event handlers</a>
(and their corresponding <a>event handler event types</a>) that must be supported,
as <a>event handler IDL attributes</a>, by all objects implementing the {{MediaQueryList}} interface:

<table class="complex data">
 <thead>
  <tr>
   <th><a>Event handler</a>
   <th><a>Event handler event type</a>
 <tbody>
  <tr>
   <td><dfn attribute for=MediaQueryList>onchange</dfn>
   <td><a event>change</a>
</table>

<wpt>
    MediaQueryList-addListener-handleEvent.html
    MediaQueryList-addListener-removeListener.html
    MediaQueryList-change-event-matches-value.html
    MediaQueryList-extends-EventTarget-interop.html
    MediaQueryList-extends-EventTarget.html
    MediaQueryListEvent.html
</wpt>

<pre class=idl>
[Exposed=Window]
interface MediaQueryListEvent : Event {
  constructor(CSSOMString type, optional MediaQueryListEventInit eventInitDict = {});
  readonly attribute CSSOMString media;
  readonly attribute boolean matches;
};

dictionary MediaQueryListEventInit : EventInit {
  CSSOMString media = "";
  boolean matches = false;
};
</pre>

The <dfn attribute for=MediaQueryListEvent>media</dfn> attribute must return the value it was initialized to.

The <dfn attribute for=MediaQueryListEvent>matches</dfn> attribute must return the value it was initialized to.


<h4 id=mediaquerylist-event-summary>Event summary</h4>

<i>This section is non-normative.</i>

<table class="complex data">
 <thead>
  <tr>
   <th>Event
   <th>Interface
   <th>Interesting targets
   <th>Description
 <tbody>
  <tr>
   <td><dfn event for=MediaQueryList>change</dfn>
   <td>{{MediaQueryListEvent}}
   <td>{{MediaQueryList}}
   <td>Fired at the {{MediaQueryList}} when the <a>matches state</a> changes.
</table>

<h3 id=the-screen-interface>The {{Screen}} Interface</h3>

As its name suggests, the {{Screen}} interface represents information about the screen of the output device.

<pre class=idl>
[Exposed=Window]
interface Screen {
  readonly attribute long availWidth;
  readonly attribute long availHeight;
  readonly attribute long width;
  readonly attribute long height;
  readonly attribute unsigned long colorDepth;
  readonly attribute unsigned long pixelDepth;
};
</pre>

The <dfn attribute for=Screen>availWidth</dfn> attribute must return the width of the <a>Web-exposed
available screen area</a>. <!--fingerprint-->

The <dfn attribute for=Screen>availHeight</dfn> attribute must return the height of the
<a>Web-exposed available screen area</a>. <!--fingerprint-->

The <dfn attribute for=Screen>width</dfn> attribute must return the width of the <a>Web-exposed
screen area</a>. <!--fingerprint-->

The <dfn attribute for=Screen>height</dfn> attribute must return the height of the <a>Web-exposed
screen area</a>. <!--fingerprint-->

The <dfn attribute for=Screen>colorDepth</dfn> and <dfn attribute
for=Screen>pixelDepth</dfn> attributes should return the number of bits
allocated to colors for a pixel in the output device, excluding the alpha
channel. If the user agent is not able to return the number of bits used by the
output device, it should return the closest estimation such as, for example, the
number of bits used by the frame buffer sent to the display or any internal
representation that would be the closest to the value the output device would
use. The user agent must return a value for these attributes at least equal to
the value of the '@media/color' media feature multiplied by three. If the different
color components are not represented with the same number of bits, the returned
value may be greater than three times the value of the '@media/color' media feature. If the user
agent does not know the color depth or does not want to return it for privacy
considerations, it should return 24.

Note: The {{colorDepth}} and {{pixelDepth}} attributes return the same value for
compatibility reasons.

Note: Some non-conforming implementations are known to return 32 instead of 24.

<wpt>
    cssom-view-window-screen-interface.html
    screen-detached-frame.html
    Screen-pixelDepth-Screen-colorDepth001.html
</wpt>

<h2 id=extensions-to-the-document-interface>Extensions to the {{Document}} Interface</h2>

<pre class=idl>
partial interface Document {
  Element? elementFromPoint(double x, double y);
  sequence&lt;Element> elementsFromPoint(double x, double y);
  CaretPosition? caretPositionFromPoint(double x, double y, optional <span>CaretPositionFromPointOptions</span> options = {});
  readonly attribute Element? scrollingElement;
};

dictionary <dfn dictionary>CaretPositionFromPointOptions</dfn> {
  sequence&lt;ShadowRoot> <dfn dict-member for="CaretPositionFromPointOptions">shadowRoots</dfn> = [];
};
</pre>

The <dfn method for=Document caniuse=element-from-point>elementFromPoint(<var>x</var>, <var>y</var>)</dfn> method must follow these steps:

1. If either argument is negative, <var>x</var> is greater than the <a>viewport</a> width excluding the size of a rendered scroll bar (if any), or
    <var>y</var> is greater than the <a>viewport</a> height excluding the size of a rendered scroll bar (if any), or there is no <a>viewport</a>
    associated with the document, return null and terminate these steps.
1. If there is a [=CSS/box=] in the <a>viewport</a> that would be a target for hit testing at coordinates <var>x</var>,<var>y</var>,
    when applying the <a>transforms</a> that apply to the descendants of the <a>viewport</a>, return the associated element and terminate these steps.
1. If the document has a [=root element=], return the [=root element=] and terminate these steps.
1. Return null.

Note: The {{elementFromPoint()}} method does not necessarily return the top-most painted element. For
instance, an element can be excluded from being a target for hit testing by using the 'pointer-events' CSS property.

<wpt>
    elementFromPoint-001.html
    elementFromPoint-002.html
    elementFromPoint-003.html
    elementFromPoint-dynamic-anon-box.html
    elementFromPoint-ellipsis-in-inline-box.html
    elementFromPoint-float-in-relative.html
    elementFromPoint-float-in-table.html
    elementFromPoint-list-001.html
    elementFromPoint-mixed-font-sizes.html
    elementFromPoint-parameters.html
    elementFromPoint-subpixel.html
    elementFromPoint-visibility-hidden-resizer.html
    elementFromPoint.html
    elementFromPosition.html
    negativeMargins.html
</wpt>

<p>
    The <dfn method for=Document>elementsFromPoint(<var>x</var>, <var>y</var>)</dfn> method must follow these steps:

1. Let <var>sequence</var> be a new empty sequence.
1. If either argument is negative, <var>x</var> is greater than the <a>viewport</a> width excluding the size of a rendered scroll bar (if any), or
    <var>y</var> is greater than the <a>viewport</a> height excluding the size of a rendered scroll bar (if any), or there is no <a>viewport</a>
    associated with the document, return <var>sequence</var> and terminate these steps.
1. For each [=CSS/box=] in the <a>viewport</a>, in paint order, starting with the topmost box, that would be a target for hit testing at
    coordinates <var>x</var>,<var>y</var> even if nothing would be overlapping it, when applying the <a>transforms</a> that apply to the descendants of the
    <a>viewport</a>, append the associated element to <var>sequence</var>.
1. If the document has a [=root element=], and the last item in <var>sequence</var> is not the [=root element=], append the [=root element=] to <var>sequence</var>.
1. Return <var>sequence</var>.

<wpt>
    elementsFromPoint-iframes.html
    elementsFromPoint-inline-htb-ltr.html
    elementsFromPoint-inline-htb-rtl.html
    elementsFromPoint-inline-vlr-ltr.html
    elementsFromPoint-inline-vlr-rtl.html
    elementsFromPoint-inline-vrl-ltr.html
    elementsFromPoint-inline-vrl-rtl.html
    elementsFromPoint-invalid-cases.html
    elementsFromPoint-shadowroot.html
    elementsFromPoint-simple.html
    elementsFromPoint-svg-text.html
    elementsFromPoint-svg.html
    elementsFromPoint-table.html
    elementsFromPoint.html
</wpt>

The <dfn method for=Document>caretPositionFromPoint(<var>x</var>, <var>y</var>, <var>options</var>)</dfn> method must return the
result of running these steps:

1. If there is no <a>viewport</a> associated with the document, return null.
1. If either argument is negative, <var>x</var> is greater
    than the <a>viewport</a> width excluding the size of a rendered
    scroll bar (if any), <var>y</var> is greater than the
    <a>viewport</a> height excluding the size of a rendered scroll bar
    (if any) return null.
1. If at the coordinates <var>x</var>,<var>y</var>
    in the <a>viewport</a> no text insertion point indicator would have
    been inserted when applying the <a>transforms</a> that apply to the descendants of the <a>viewport</a>, return null.
1. If at the coordinates <var>x</var>,<var>y</var>
    in the <a>viewport</a> a text insertion point indicator would have
    been inserted in a text entry widget which is also a replaced element, when applying the <a>transforms</a> that apply to the descendants of the
    <a>viewport</a>, return a <a>caret position</a> with its properties set as follows:

    <dl>
        <dt><a>caret node</a>
        <dd>The node corresponding to the text entry widget.

        <dt><a>caret offset</a>
        <dd>The amount of 16-bit units to the left of where the
        text insertion point indicator would have inserted.
    </dl>
1. Otherwise:

    1. Let <var>caretPosition</var> be a <a for=/>tuple</a> consisting of a <var>caretPositionNode</var> (a <a for=/>node</a>) and a <var>caretPositionOffset</var> (a non-negative integer) for the position where the text insertion point indicator would have been inserted when applying
        the <a>transforms</a> that apply to the descendants of the <a>viewport</a>.
    1. Let <var>startNode</var> be the <var>caretPositionNode</var> of the <var>caretPosition</var>, and let <var>startOffset</var> be the <var>caretPositionOffset</var> of the <var>caretPosition</var>.
    1. While <var>startNode</var> is a [=node=], <var>startNode</var>'s [=tree/root=] is a [=shadow root=], and <var>startNode</var>'s [=tree/root=] is not a [=shadow-including inclusive ancestor=] of any of <var>options</var>["{{CaretPositionFromPointOptions/shadowRoots}}"], repeat these steps:
        1. Set <var>startOffset</var> to [=tree/index=] of <var>startNode</var>'s [=tree/root=]'s [=host=].
        1. Set <var>startNode</var> to <var>startNode</var>'s [=tree/root=]'s [=host=]'s [=tree/parent=].
    1. Return a <a>caret position</a> with its properties set as follows:
        1. <a>caret node</a> is set to <var>startNode</var>.
        1. <a>caret offset</a> is set to <var>startOffset</var>.

Note: This <a>caret position</a> is not <a spec=html>live</a>.

Note: The specifics of hit testing are out of scope of this
specification and therefore the exact details of
{{elementFromPoint()}} and {{caretPositionFromPoint()}}
are therefore too. Hit testing will hopefully be defined in a future
revision of CSS or HTML.

<p>The <dfn attribute for=Document caniuse=document-scrollingelement>scrollingElement</dfn> attribute, on getting, must run these steps:

1. If the {{Document}} is in <a>quirks mode</a>, follow these substeps:
    1. If <a>the <code>body</code> element</a> exists, and it is not <a>potentially scrollable</a>, return <a>the <code>body</code> element</a> and abort these steps.

        For this purpose,
        a value of ''overflow:clip'' on the <a>the <code>body</code> element</a>'s parent element
        must be treated as ''overflow:hidden''.
    1. Return null and abort these steps.
1. If there is a [=root element=], return the [=root element=] and abort these steps.
1. Return null.

Note: For non-conforming user agents that always use the <a>quirks mode</a> behavior for {{Element/scrollTop}}
and {{Element/scrollLeft}}, the {{Document/scrollingElement}} attribute is expected to also always return
<a>the <code>body</code> element</a> (or null if it does not exist).
This API exists so that Web developers can use it to get the right element to use for scrolling APIs,
without making assumptions about a particular user agent's behavior
or having to invoke a scroll to see which element scrolls the viewport.

Note: <a>the <code>body</code> element</a> is different from HTML's <code>document.body</code>
in that the latter can return a <code>frameset</code> element.

<wpt>
    scroll-overflow-clip-quirks-001.html
    scroll-overflow-clip-quirks-002.html
    scrollingElement-quirks-dynamic-001.html
    scrollingElement-quirks-dynamic-002.html
    scrollingElement.html
</wpt>

<h3 id=the-caretposition-interface>The {{CaretPosition}} Interface</h3>

A <dfn>caret position</dfn> gives the position of a text insertion point indicator. It always has an associated
<dfn>caret node</dfn> and <dfn>caret offset</dfn>. It is represented by a {{CaretPosition}} object.

<pre class=idl>
[Exposed=Window]
interface CaretPosition {
  readonly attribute Node offsetNode;
  readonly attribute unsigned long offset;
  [NewObject] DOMRect? getClientRect();
};
</pre>

The <dfn attribute for=CaretPosition>offsetNode</dfn> attribute must return the <a>caret node</a>.

The <dfn attribute for=CaretPosition>offset</dfn> attribute must return the <a>caret offset</a>.

The <dfn method for=CaretPosition>getClientRect()</dfn> method must follow these steps,
aborting on the first step that returns a value:

1. If <a>caret node</a> is a text entry widget that is a replaced element,
    and that is in the document,
    return a [=scaled=] {{DOMRect}} object for the caret in the widget
    as represented by the <a>caret offset</a> value.
    The <a>transforms</a> that apply to the element and its ancestors are applied.
1. Otherwise:

    1. Let <var>caretRange</var> be a collapsed {{Range}} object whose [=range/start node=] and [=range/end node=] are set to <a>caret node</a>, and whose [=range/start offset=] and [=range/end offset=] are set to <a>caret offset</a>.
    1. Return the {{DOMRect}} object which is the result of invoking the {{Range/getBoundingClientRect()}} method on <var>caretRange</var>.

Note: This {{DOMRect}} object is not <a spec=html>live</a>.

<wpt>
    CaretPosition-001.html
</wpt>

<h2 id=extension-to-the-element-interface caniuse="element-scroll-methods">
Extensions to the {{Element}} Interface</h2>

<pre class=idl>
enum ScrollLogicalPosition { "start", "center", "end", "nearest" };
dictionary ScrollIntoViewOptions : ScrollOptions {
  ScrollLogicalPosition block = "start";
  ScrollLogicalPosition inline = "nearest";
  ScrollIntoViewContainer container = "all";
};

enum ScrollIntoViewContainer { "all", "nearest" };

dictionary CheckVisibilityOptions {
    boolean checkOpacity = false;
    boolean checkVisibilityCSS = false;
    boolean contentVisibilityAuto = false;
    boolean opacityProperty = false;
    boolean visibilityProperty = false;
};

partial interface Element {
  DOMRectList getClientRects();
  [NewObject] DOMRect getBoundingClientRect();

  boolean checkVisibility(optional CheckVisibilityOptions options = {});

  Promise&lt;undefined> scrollIntoView(optional (boolean or ScrollIntoViewOptions) arg = {});
  Promise&lt;undefined> scroll(optional ScrollToOptions options = {});
  Promise&lt;undefined> scroll(unrestricted double x, unrestricted double y);
  Promise&lt;undefined> scrollTo(optional ScrollToOptions options = {});
  Promise&lt;undefined> scrollTo(unrestricted double x, unrestricted double y);
  Promise&lt;undefined> scrollBy(optional ScrollToOptions options = {});
  Promise&lt;undefined> scrollBy(unrestricted double x, unrestricted double y);
  attribute unrestricted double scrollTop;
  attribute unrestricted double scrollLeft;
  readonly attribute long scrollWidth;
  readonly attribute long scrollHeight;
  readonly attribute long clientTop;
  readonly attribute long clientLeft;
  readonly attribute long clientWidth;
  readonly attribute long clientHeight;
  readonly attribute double currentCSSZoom;
};
</pre>

Issue: Should the scroll methods above return a result object and if so what information should they provide? #12495

Note: The {{CheckVisibilityOptions/checkOpacity}} and {{CheckVisibilityOptions/checkVisibilityCSS}} properties are historical names.
These properties have aliases that match the new naming scheme,
namely {{CheckVisibilityOptions/opacityProperty}} and {{CheckVisibilityOptions/visibilityProperty}}.

The <dfn method for=Element>getClientRects()</dfn> method, when invoked, must return the result of the following algorithm:

1. If the element on which it was invoked does not have an associated [=CSS/box=] return an empty {{DOMRectList}} object and stop this algorithm.
1. If the element has an associated <a>SVG layout box</a> return a [=scaled=] {{DOMRectList}} object containing a single {{DOMRect}} object that describes the bounding box of the element as defined by the SVG specification, applying the <a>transforms</a> that apply to the element and its ancestors.
1. Return a {{DOMRectList}} object containing {{DOMRect}} objects in content order, one for each <a spec=css-break>box fragment</a>, describing its border area (including those with a height or width of zero) with the following constraints:

    * Apply the <a>transforms</a> that apply to the element and its ancestors.
    * If the element on which the method was invoked has a computed value for the 'display' property of ''table'' or ''inline-table'' include both the table box and the caption box, if any, but not the anonymous container box.
    * Replace each [=anonymous=] [=block box=] with its child box(es) and repeat this until no anonymous block boxes are left in the final list.

Note: The {{DOMRect}} objects returned by {{Element/getClientRects()}} are not <a spec=html>live</a>.

<wpt>
    cssom-getClientRects-002.html
    cssom-getClientRects.html
    DOMRectList.html
    getClientRects-br-htb-ltr.html
    getClientRects-br-htb-rtl.html
    getClientRects-br-vlr-ltr.html
    getClientRects-br-vlr-rtl.html
    getClientRects-br-vrl-ltr.html
    getClientRects-br-vrl-rtl.html
    getClientRects-inline-atomic-child.html
    getClientRects-inline-inline-child.html
    getClientRects-inline.html
    getClientRects-zoom.html
    historical.html
    ttwf-js-cssomview-getclientrects-length.html
</wpt>

The <dfn method for=Element caniuse=getboundingclientrect>getBoundingClientRect()</dfn> method, when
invoked on an element <var>element</var>, must return the result of
<a>getting the bounding box</a> for <var>element</var>.

<div algorithm>
To <dfn export for=Element>get the bounding box</dfn> for <var>element</var>,
run the following steps:
    1. Let <var>list</var> be the result of invoking {{Element/getClientRects()}} on
        <var>element</var>.
    1. If the <var>list</var> is empty return a {{DOMRect}} object whose {{DOMRect/x}},
        {{DOMRect/y}}, {{DOMRect/width}} and {{DOMRect/height}} members are zero.
    1. If all rectangles in <var>list</var> have zero width or height, return the first rectangle in
        <var>list</var>.
    1. Otherwise, return a {{DOMRect}} object describing the smallest rectangle that includes all
        of the rectangles in <var>list</var> of which the height or width is not zero.
</div>

Note: The {{DOMRect}} object returned by {{Element/getBoundingClientRect()}} is not <a spec=html>live</a>.

<div class='example'>
    The following snippet gets the dimensions of the first <code>div</code> element in a document:

    <pre highlight=javascript>
    var example = document.getElementsByTagName("div")[0].getBoundingClientRect();
    var exampleWidth = example.width;
    var exampleHeight = example.height;
    </pre>
</div>

<wpt>
    cssom-getBoundingClientRect-001.html
    cssom-getBoundingClientRect-002.html
    cssom-getBoundingClientRect-003.html
    cssom-getBoundingClientRect-vertical-rl.html
    getBoundingClientRect-empty-inline.html
    getBoundingClientRect-newline.html
    getBoundingClientRect-scroll.html
    getBoundingClientRect-shy.html
    getBoundingClientRect-svg.html
    getBoundingClientRect-zoom.html
    GetBoundingRect.html
</wpt>

<div algorithm>
    Note: The {{Element/checkVisibility()}} method
    provides a set of simple checks
    for whether an element is potentially "visible".
    It defaults to a very simple and straightforward method
    based on the [=box tree=],
    but allows for several additional checks to be opted into,
    depending on what precise notion of "visibility" is desired.

    The <dfn method for=Element>checkVisibility(|options|)</dfn> method
    must run these steps,
    when called on an element |this|:

    1. If |this| does not have an associated [=CSS/box=],
        return false.
    1. If an ancestor of |this| in the [=flat tree=]
        has ''content-visibility: hidden'',
        return false.
    1. If either the {{CheckVisibilityOptions/opacityProperty}}
        or the {{CheckVisibilityOptions/checkOpacity}}
        dictionary members of |options|
        are true,
        and |this|, or an ancestor of |this| in the [=flat tree=],
        has a computed 'opacity' value of ''0'',
        return false.
    1. If either the {{CheckVisibilityOptions/visibilityProperty}}
        or the {{CheckVisibilityOptions/checkVisibilityCSS}}
        dictionary members of |options|
        are true,
        and |this| is <l spec=css-display>[=invisible=]</l>,
        return false.
    1. If the {{CheckVisibilityOptions/contentVisibilityAuto}} dictionary member of |options|
        is true
        and an ancestor of |this| in the [=flat tree=]
        [=skips its contents=]
        due to ''content-visibility: auto'',
        return false.
    1. Return true.
</div>

<wpt>
    checkVisibility.html
</wpt>

The <dfn method for=Element caniuse=scrollintoview>scrollIntoView(<var>arg</var>)</dfn> method must run these steps:

1. Let <var>behavior</var> be "<code>auto</code>".
1. Let <var>block</var> be "<code>start</code>".
1. Let <var>inline</var> be "<code>nearest</code>".
1. Let <var>container</var> be <code>null</code>.
1. If <var>arg</var> is a {{ScrollIntoViewOptions}} dictionary, then:
    1. Set <var>behavior</var> to the {{ScrollOptions/behavior}} dictionary member of <var>options</var>.
    1. Set <var>block</var> to the {{ScrollIntoViewOptions/block}} dictionary member of <var>options</var>.
    1. Set <var>inline</var> to the {{ScrollIntoViewOptions/inline}} dictionary member of <var>options</var>.
    1. If the {{ScrollIntoViewOptions/container}} dictionary member of <var>options</var> is "<code>nearest</code>",
        set <var>container</var> to the element.
1. Otherwise, if <var>arg</var> is false, then set <var>block</var> to "<code>end</code>".
1. If the element does not have any associated [=CSS/box=],
    or is not available to user-agent features,
    then return a resolved {{Promise}} and abort the remaining steps.
1. <a lt='scroll a target into view'>Scroll the element into view</a>
    with <var>behavior</var>, <var>block</var>, <var>inline</var>, and <var>container</var>.
    Let <var>scrollPromise</var> be the {{Promise}} returned from this step
1. Optionally perform some other action that brings the element to the user's attention.
1. Return <var>scrollPromise</var>.

<div class='example'>
    A component can use scrollIntoView to scroll content of interest into the specified alignment:

    <pre><code highlight="html">
    &lt;style&gt;
        .scroller { overflow: auto; scroll-padding: 8px; }
        .slide { scroll-margin: 16px; scroll-snap-align: center; }
    &lt;/style&gt;
    &lt;div class="carousel"&gt;
        &lt;div class="slides scroller"&gt;
            &lt;div id="s1" class="slide"&gt;
            &lt;div id="s2" class="slide"&gt;
            &lt;div id="s3" class="slide"&gt;
        &lt;/div&gt;
        &lt;div class="markers"&gt;
            &lt;button data-target="s1"&gt;1&lt;/button&gt;
            &lt;button data-target="s2"&gt;2&lt;/button&gt;
            &lt;button data-target="s3"&gt;3&lt;/button&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;script&gt;
        document.querySelector('.markers').addEventListener('click', (evt) => {
            const target = document.getElementById(evt.target.dataset.target);
            if (!target) return;
            // scrollIntoView correctly aligns target item respecting scroll-snap-align,
            // scroll-margin, and the scroll container's scroll-padding.
            target.scrollIntoView({
                // Only scroll the nearest scroll container.
                container: 'nearest',
                behavior: 'smooth'
            });
        });
    &lt;/script&gt;
    </code></pre>
</div>

<wpt>
    scrollIntoView-align-scrollport-covering-child.html
    scrollIntoView-container.html
    scrollintoview-containingblock-chain.html
    scrollIntoView-fixed-outside-of-viewport.html
    scrollIntoView-fixed.html
    scrollIntoView-horizontal-partially-visible.html
    scrollIntoView-horizontal-tb-writing-mode-and-rtl-direction.html
    scrollIntoView-horizontal-tb-writing-mode.html
    scrollIntoView-inline-image.html
    scrollIntoView-multiple-nested.html
    scrollIntoView-multiple.html
    scrollIntoView-scrolling-container.html
    scrollIntoView-scrollMargin.html
    scrollIntoView-scrollPadding.html
    scrollIntoView-shadow.html
    scrollIntoView-should-treat-slot-as-scroll-container.html
    scrollIntoView-sideways-lr-writing-mode-and-rtl-direction.html
    scrollIntoView-sideways-lr-writing-mode.html
    scrollIntoView-sideways-rl-writing-mode-and-rtl-direction.html
    scrollIntoView-sideways-rl-writing-mode.html
    scrollIntoView-smooth.html
    scrollIntoView-stuck.tentative.html
    scrollIntoView-svg-shape.html
    scrollIntoView-vertical-lr-writing-mode-and-rtl-direction.html
    scrollIntoView-vertical-lr-writing-mode.html
    scrollIntoView-vertical-rl-writing-mode.html
    scrollintoview-zero-height-item.html
    scrollintoview.html
    smooth-scrollIntoView-with-smooth-fragment-scroll.html
    smooth-scrollIntoView-with-unrelated-gesture-scroll.html
    visual-scrollIntoView-001.html
    visual-scrollIntoView-002.html
    visual-scrollIntoView-003.html
</wpt>

The <dfn method for=Element lt="scroll(options)|scroll(x, y)">scroll()</dfn> method must run these steps:

1. If invoked with one argument, follow these substeps:
    1. Let <var>options</var> be the argument.
    1. <a>Normalize non-finite values</a> for {{ScrollToOptions/left}} and {{ScrollToOptions/top}} dictionary members of <var>options</var>, if present.
    1. Let <var>x</var> be the value of the {{ScrollToOptions/left}} dictionary member of <var>options</var>, if present, or the element's current scroll position on the x axis otherwise.
    1. Let <var>y</var> be the value of the {{ScrollToOptions/top}} dictionary member of <var>options</var>, if present, or the element's current scroll position on the y axis otherwise.
1. If invoked with two arguments, follow these substeps:
    1. Let <var>options</var> be null <a lt="converted to an IDL value">converted</a> to a {{ScrollToOptions}} dictionary. [[!WEBIDL]]
    1. Let <var>x</var> and <var>y</var> be the arguments, respectively.
    1. <a>Normalize non-finite values</a> for <var>x</var> and <var>y</var>.
    1. Let the {{ScrollToOptions/left}} dictionary member of <var>options</var> have the value <var>x</var>.
    1. Let the {{ScrollToOptions/top}} dictionary member of <var>options</var> have the value <var>y</var>.
1. Let <var>document</var> be the element's <a>node document</a>.
1. If <var>document</var> is not the <a>active document</a>, return a resolved {{Promise}} and abort the remaining steps.
1. Let <var>window</var> be the value of <var>document</var>'s {{Document/defaultView}} attribute.
1. If <var>window</var> is null, return a resolved {{Promise}} and abort the remaining steps.
1. If the element is the [=root element=] and <var>document</var> is in <a>quirks mode</a>, return a resolved {{Promise}} and abort the remaining steps.
1. If the element is the [=root element=], return the {{Promise}} returned by {{Window/scroll()}} on <var>window</var> after the method is invoked with
    {{Window/scrollX}} on <var>window</var> as first argument and <var>y</var> as second argument, and abort the remaining steps.
1. If the element is <a>the <code>body</code> element</a>,
    <var>document</var> is in <a>quirks mode</a>,
    and the element is not <a>potentially scrollable</a>,
    return the {{Promise}} returned by {{Window/scroll()}} on <var>window</var> after the method is invoked with
    <var>options</var> as the only argument, and abort the remaining steps.
1. If the element does not have any associated [=CSS/box=],
    the element has no associated <a>scrolling box</a>,
    or the element has no overflow,
    return a resolved {{Promise}} and abort the remaining steps.
1. <a lt='scroll an element'>Scroll the element</a> to <var>x</var>,<var>y</var>,
    with the scroll behavior being the value of the {{ScrollOptions/behavior}} dictionary member of <var>options</var>.  Let <var>scrollPromise</var> be the {{Promise}} returned from this step.
1. Return <var>scrollPromise</var>.

When the <dfn method for=Element lt="scrollTo(options)|scrollTo(x, y)">scrollTo()</dfn> method is invoked, the
user agent must act as if the {{Element/scroll()}} method was invoked with the same arguments.

When the <dfn method for=Element lt="scrollBy(options)|scrollBy(x, y)">scrollBy()</dfn> method is invoked, the
user agent must run these steps:

1. If invoked with one argument, follow these substeps:
    1. Let <var>options</var> be the argument.
    1. <a>Normalize non-finite values</a> for {{ScrollToOptions/left}} and {{ScrollToOptions/top}} dictionary members of <var>options</var>, if present.
1. If invoked with two arguments, follow these substeps:
    1. Let <var>options</var> be null <a lt="converted to an IDL value">converted</a> to a {{ScrollToOptions}} dictionary. [[!WEBIDL]]
    1. Let <var>x</var> and <var>y</var> be the arguments, respectively.
    1. <a>Normalize non-finite values</a> for <var>x</var> and <var>y</var>.
    1. Let the {{ScrollToOptions/left}} dictionary member of <var>options</var> have the value <var>x</var>.
    1. Let the {{ScrollToOptions/top}} dictionary member of <var>options</var> have the value <var>y</var>.
1. Add the value of {{Element/scrollLeft}} to the {{ScrollToOptions/left}} dictionary member.
1. Add the value of {{Element/scrollTop}} to the {{ScrollToOptions/top}} dictionary member.
1. Return the {{Promise}} returned by {{Element/scroll()}} after the method is invoked with <var>options</var> as the only argument.

<wpt>
    window-scrollBy-display-change.html
</wpt>

The <dfn attribute for=Element>scrollTop</dfn> attribute, on getting, must return the result of running these steps:

1. Let <var>document</var> be the element's <a>node document</a>.
1. If <var>document</var> is not the <a>active document</a>, return zero and terminate these steps.
1. Let <var>window</var> be the value of <var>document</var>'s {{Document/defaultView}} attribute.
1. If <var>window</var> is null, return zero and terminate these steps.
1. If the element is the [=root element=] and <var>document</var> is in <a>quirks mode</a>, return zero and terminate these steps.
1. If the element is the [=root element=] return the value of {{Window/scrollY}} on <var>window</var>.
1. If the element is <a>the <code>body</code> element</a>, <var>document</var> is in <a>quirks mode</a>, and the element is not <a>potentially scrollable</a>, return the value of {{Window/scrollY}} on <var>window</var>.
1. If the element does not have any associated [=CSS/box=], return zero and terminate these steps.
1. Return the y-coordinate of the <a>scrolling area</a> at the alignment point with the top of the <a>padding edge</a> of the element.

When setting the {{Element/scrollTop}} attribute these steps must be run:

1. Let <var>y</var> be the given value.
1. <a>Normalize non-finite values</a> for <var>y</var>.
1. Let <var>document</var> be the element's <a>node document</a>.
1. If <var>document</var> is not the <a>active document</a>, terminate these steps.
1. Let <var>window</var> be the value of <var>document</var>'s {{Document/defaultView}} attribute.
1. If <var>window</var> is null, terminate these steps.
1. If the element is the [=root element=] and <var>document</var> is in <a>quirks mode</a>, terminate these steps.
1. If the element is the [=root element=] invoke {{Window/scroll()}} on <var>window</var> with {{Window/scrollX}} on <var>window</var> as first argument and <var>y</var> as second argument, and terminate these steps.
1. If the element is <a>the <code>body</code> element</a>, <var>document</var> is in <a>quirks mode</a>, and the element is not <a>potentially scrollable</a>, invoke {{Window/scroll()}} on <var>window</var> with {{Window/scrollX}} as first argument and <var>y</var> as second argument, and terminate these steps.
1. If the element does not have any associated [=CSS/box=], the element has no associated <a>scrolling box</a>, or the element has no overflow, terminate these steps.
1. <a lt='scroll an element'>Scroll the element</a> to {{Element/scrollLeft}},<var>y</var>, with the scroll behavior being "<code>auto</code>".

<wpt>
    dom-element-scroll.html
    elementScroll-002.html
    elementScroll.html
    scroll-no-layout-box.html
    scroll-offsets-fractional-zoom.html
    scroll-zoom.html
    scrollTop-display-change.html
    table-scroll-props.html
</wpt>

The <dfn attribute for=Element>scrollLeft</dfn> attribute, on getting, must return the result of running these steps:

1. Let <var>document</var> be the element's <a>node document</a>.
1. If <var>document</var> is not the <a>active document</a>, return zero and terminate these steps.
1. Let <var>window</var> be the value of <var>document</var>'s {{Document/defaultView}} attribute.
1. If <var>window</var> is null, return zero and terminate these steps.
1. If the element is the [=root element=] and <var>document</var> is in <a>quirks mode</a>, return zero and terminate these steps.
1. If the element is the [=root element=] return the value of {{Window/scrollX}} on <var>window</var>.
1. If the element is <a>the <code>body</code> element</a>, <var>document</var> is in <a>quirks mode</a>, and the element is not <a>potentially scrollable</a>, return the value of {{Window/scrollX}} on <var>window</var>.
1. If the element does not have any associated [=CSS/box=], return zero and terminate these steps.
1. Return the x-coordinate of the <a>scrolling area</a> at the alignment point with the left of the <a>padding edge</a> of the element.

When setting the {{Element/scrollLeft}} attribute these steps must be run:

1. Let <var>x</var> be the given value.
1. <a>Normalize non-finite values</a> for <var>x</var>.
1. Let <var>document</var> be the element's <a>node document</a>.
1. If <var>document</var> is not the <a>active document</a>, terminate these steps.
1. Let <var>window</var> be the value of <var>document</var>'s {{Document/defaultView}} attribute.
1. If <var>window</var> is null, terminate these steps.
1. If the element is the [=root element=] and <var>document</var> is in <a>quirks mode</a>, terminate these steps.
1. If the element is the [=root element=] invoke {{Window/scroll()}} on <var>window</var> with <var>x</var> as first argument and {{Window/scrollY}} on <var>window</var> as second argument, and terminate these steps.
1. If the element is <a>the <code>body</code> element</a>, <var>document</var> is in <a>quirks mode</a>, and the element is not <a>potentially scrollable</a>, invoke {{Window/scroll()}} on <var>window</var> with <var>x</var> as first argument and {{Window/scrollY}} on <var>window</var> as second argument, and terminate these steps.
1. If the element does not have any associated [=CSS/box=], the element has no associated <a>scrolling box</a>, or the element has no overflow, terminate these steps.
1. <a lt='scroll an element'>Scroll the element</a> to <var>x</var>,{{Element/scrollTop}}, with the scroll behavior being "<code>auto</code>".

<wpt>
    scrollLeft-of-scroller-with-wider-scrollbar.html
    scrollLeftTop.html
</wpt>

The <dfn attribute for=Element>scrollWidth</dfn> attribute must return the result of running these steps:

1. Let <var>document</var> be the element's <a>node document</a>.
1. If <var>document</var> is not the <a>active document</a>, return zero and terminate these steps.
1. Let <var>viewport width</var> be the width of the <a>viewport</a> excluding the width of the scroll bar, if any, or zero if there is no <a>viewport</a>.
1. If the element is the [=root element=] and <var>document</var> is not in <a>quirks mode</a> return max(<a>viewport</a> <a>scrolling area</a> width, <var>viewport width</var>).
1. If the element is <a>the <code>body</code> element</a>, <var>document</var> is in <a>quirks mode</a> and the element is not <a>potentially scrollable</a>, return max(<a>viewport</a> <a>scrolling area</a> width, <var>viewport width</var>).
1. If the element does not have any associated [=CSS/box=] return zero and terminate these steps.
1. Return the width of the element's <a>scrolling area</a>.

<wpt>
    pt-to-px-width.html
    scrollWidthHeight-contain-layout.html
    scrollWidthHeight-negative-margin-001.html
    scrollWidthHeight-negative-margin-002.html
    scrollWidthHeight-overflow-visible-margin-collapsing.html
    scrollWidthHeight-overflow-visible-negative-margins.html
    scrollWidthHeight.xht
    scrollWidthHeightWhenNotScrollable.xht
</wpt>

The <dfn attribute for=Element>scrollHeight</dfn> attribute must return the result of running these steps:

1. Let <var>document</var> be the element's <a>node document</a>.
1. If <var>document</var> is not the <a>active document</a>, return zero and terminate these steps.
1. Let <var>viewport height</var> be the height of the <a>viewport</a> excluding the height of the scroll bar, if any, or zero if there is no <a>viewport</a>.
1. If the element is the [=root element=] and <var>document</var> is not in <a>quirks mode</a> return max(<a>viewport</a> <a>scrolling area</a> height, <var>viewport height</var>).
1. If the element is <a>the <code>body</code> element</a>, <var>document</var> is in <a>quirks mode</a> and the element is not <a>potentially scrollable</a>, return max(<a>viewport</a> <a>scrolling area</a> height, <var>viewport height</var>).
1. If the element does not have any associated [=CSS/box=] return zero and terminate these steps.
1. Return the height of the element's <a>scrolling area</a>.

The <dfn attribute for=Element>clientTop</dfn> attribute must run these steps:

1. If the element has no associated [=CSS/box=] or if the [=CSS/box=] is inline, return zero.
1. Return the [=unscaled=] computed value of the 'border-top-width' property plus the height of any scrollbar rendered between the top <a>padding edge</a> and the top <a>border edge</a>, ignoring any <a>transforms</a> that apply to the element and its ancestors.

<wpt>
    client-props-inline-list-item.html
    client-props-input.html
    client-props-root.html
    client-props-zoom.html
    outer-svg.html
    table-client-props.html
</wpt>

The <dfn attribute for=Element>clientLeft</dfn> attribute must run these steps:

1. If the element has no associated [=CSS/box=] or if the [=CSS/box=] is inline, return zero.
1. Return the [=unscaled=] computed value of the 'border-left-width' property plus the width of any scrollbar rendered between the left <a>padding edge</a> and the left <a>border edge</a>, ignoring any <a>transforms</a> that apply to the element and its ancestors.

The <dfn attribute for=Element>clientWidth</dfn> attribute must run these steps:

1. If the element has no associated [=CSS/box=] or if the [=CSS/box=] is inline, return zero.
1. If the element is the [=root element=] and the element's <a>node document</a> is not in <a>quirks mode</a>, or if the element is <a>the <code>body</code> element</a> and the element's <a>node document</a> <em>is</em> in <a>quirks mode</a>, return the <a>viewport</a> width excluding the size of a rendered scroll bar (if any).
1. Return the [=unscaled=] width of the <a>padding edge</a> excluding the width of any rendered scrollbar between the <a>padding edge</a> and the <a>border edge</a>, ignoring any <a>transforms</a> or that apply to the element and its ancestors.

The <dfn attribute for=Element>clientHeight</dfn> attribute must run these steps:

1. If the element has no associated [=CSS/box=] or if the [=CSS/box=] is inline, return zero.
1. If the element is the [=root element=] and the element's <a>node document</a> is not in <a>quirks mode</a>, or if the element is <a>the <code>body</code> element</a> and the element's <a>node document</a> <em>is</em> in <a>quirks mode</a>, return the <a>viewport</a> height excluding the size of a rendered scroll bar (if any).
1. Return the [=unscaled=] height of the <a>padding edge</a> excluding the height of any rendered scrollbar between the <a>padding edge</a> and the <a>border edge</a>, ignoring any <a>transforms</a> that apply to the element and its ancestors.

The <dfn attribute for=Element>currentCSSZoom</dfn> attribute must return the
[=effective zoom=] of the element, or 1.0 if the element isn't [=being rendered=].

<wpt>
    Element-currentCSSZoom.html
    table-border-collapse-client-width-height.html
    table-border-separate-client-width-height.html
    table-with-border-client-width-height.html
</wpt>

<h3 id=element-scrolling-members>{{Element}} Scrolling Members</h3>

<div algorithm>

To <dfn export>determine the scroll-into-view position</dfn> of a <var>target</var>, which is an <a for="/">Element</a>, [=pseudo-element=], or <a>Range</a>,
with a scroll behavior <var>behavior</var>,
a block flow direction position <var>block</var>,
an inline base direction position <var>inline</var>,
and a <a>scrolling box</a> <var>scrolling box</var>,
run the following steps:

1. Let <var>target bounding border box</var> be the box represented by the return value of invoking Element's {{Element/getBoundingClientRect()}}, if <var>target</var> is an <a for="/">Element</a>, or Range's {{Range/getBoundingClientRect()}}, if <var>target</var> is a <a>Range</a>.
1. Let <var>scrolling box edge A</var> be the <a>beginning edge</a> in the <a>block flow direction</a> of <var>scrolling box</var>, and let <var>element edge A</var> be <var>target bounding border box</var>'s edge on the same physical side as that of <var>scrolling box edge A</var>.
1. Let <var>scrolling box edge B</var> be the <a>ending edge</a> in the <a>block flow direction</a> of <var>scrolling box</var>, and let <var>element edge B</var> be <var>target bounding border box</var>'s edge on the same physical side as that of <var>scrolling box edge B</var>.
1. Let <var>scrolling box edge C</var> be the <a>beginning edge</a> in the <a>inline base direction</a> of <var>scrolling box</var>, and let <var>element edge C</var> be <var>target bounding border box</var>'s edge on the same physical side as that of <var>scrolling box edge C</var>.
1. Let <var>scrolling box edge D</var> be the <a>ending edge</a> in the <a>inline base direction</a> of <var>scrolling box</var>, and let <var>element edge D</var> be <var>target bounding border box</var>'s edge on the same physical side as that of <var>scrolling box edge D</var>.
1. Let <var>element height</var> be the distance between <var>element edge A</var> and <var>element edge B</var>.
1. Let <var>scrolling box height</var> be the distance between <var>scrolling box edge A</var> and <var>scrolling box edge B</var>.
1. Let <var>element width</var> be the distance between <var>element edge C</var> and <var>element edge D</var>.
1. Let <var>scrolling box width</var> be the distance between <var>scrolling box edge C</var> and <var>scrolling box edge D</var>.
1. Let <var>position</var> be the scroll position <var>scrolling box</var> would have by following these steps:

    1. If <var>block</var> is "<code>start</code>", then align <var>element edge A</var> with <var>scrolling box edge A</var>.
    1. Otherwise, if <var>block</var> is "<code>end</code>", then align <var>element edge B</var> with <var>scrolling box edge B</var>.
    1. Otherwise, if <var>block</var> is "<code>center</code>", then align the center of <var>target bounding border box</var> with the center of <var>scrolling box</var> in <var>scrolling box</var>'s <a>block flow direction</a>.
    1. Otherwise, <var>block</var> is "<code>nearest</code>":
        <dl class=switch>
            <dt>If <var>element edge A</var> and <var>element edge B</var> are both outside <var>scrolling box edge A</var> and <var>scrolling box edge B</var>
            <dd>Do nothing.

            <dt>If <var>element edge A</var> is outside <var>scrolling box edge A</var> and <var>element height</var> is less than <var>scrolling box height</var>
            <dt>If <var>element edge B</var> is outside <var>scrolling box edge B</var> and <var>element height</var> is greater than <var>scrolling box height</var>
            <dd>Align <var>element edge A</var> with <var>scrolling box edge A</var>.

            <dt>If <var>element edge A</var> is outside <var>scrolling box edge A</var> and <var>element height</var> is greater than <var>scrolling box height</var>
            <dt>If <var>element edge B</var> is outside <var>scrolling box edge B</var> and <var>element height</var> is less than <var>scrolling box height</var>
            <dd>Align <var>element edge B</var> with <var>scrolling box edge B</var>.
        </dl>
    1. If <var>inline</var> is "<code>start</code>", then align <var>element edge C</var> with <var>scrolling box edge C</var>.
    1. Otherwise, if <var>inline</var> is "<code>end</code>", then align <var>element edge D</var> with <var>scrolling box edge D</var>.
    1. Otherwise, if <var>inline</var> is "<code>center</code>", then align the center of <var>target bounding border box</var> with the center of <var>scrolling box</var> in <var>scrolling box</var>'s <a>inline base direction</a>.
    1. Otherwise, <var>inline</var> is "<code>nearest</code>":
        <dl class=switch>
            <dt>If <var>element edge C</var> and <var>element edge D</var> are both outside <var>scrolling box edge C</var> and <var>scrolling box edge D</var>
            <dd>Do nothing.

            <dt>If <var>element edge C</var> is outside <var>scrolling box edge C</var> and <var>element width</var> is less than <var>scrolling box width</var>
            <dt>If <var>element edge D</var> is outside <var>scrolling box edge D</var> and <var>element width</var> is greater than <var>scrolling box width</var>
            <dd>Align <var>element edge C</var> with <var>scrolling box edge C</var>.

            <dt>If <var>element edge C</var> is outside <var>scrolling box edge C</var> and <var>element width</var> is greater than <var>scrolling box width</var>
            <dt>If <var>element edge D</var> is outside <var>scrolling box edge D</var> and <var>element width</var> is less than <var>scrolling box width</var>
            <dd>Align <var>element edge D</var> with <var>scrolling box edge D</var>.
        </dl>
    1. If <var>target</var> is an [=/Element=], and the target element defines some <a>scroll snap positions</a>,
        then the user agent must <a>scroll snap</a> the resulting <var>position</var> to one of that element’s <a>scroll snap positions</a>
        if its nearest <a>scroll container</a> is a <a>scroll snap container</a>.
        The user agent <em>may</em> also do this even when the <a>scroll container</a> has ''scroll-snap-type: none''.
    1. Return <var>position</var>.

</div>

<div algorithm>
To <dfn export>scroll a target into view</dfn> <var>target</var>, which is an <a for="/">Element</a>, [=pseudo-element=], or <a>Range</a>,
with a scroll behavior <var>behavior</var>,
a block flow direction position <var>block</var>,
an inline base direction position <var>inline</var>,
and an optional containing <a>Element</a> to stop scrolling after reaching <var>container</var>,
means to run these steps:

1. Let <var>ancestorPromises</var> be an empty set of {{Promise}}s.
1. For each ancestor element or <a>viewport</a> that establishes a <a>scrolling box</a> <var>scrolling box</var>,
    in order of innermost to outermost <a>scrolling box</a>, run these substeps:
    1. If the {{Document}} associated with <var>target</var> is not <a>same origin</a> with the {{Document}} associated with the element or <a>viewport</a> associated with <var>scrolling box</var>, 
        abort any remaining iteration of this loop.
    1. Let <var>position</var> be the scroll position resulting from running the steps to <a>determine the scroll-into-view position</a> of <var>target</var> with <var>behavior</var> as the |scroll behavior|,
        <var>block</var> as the |block flow position|, <var>inline</var> as the |inline base direction position| and <var>scrolling box</var> as the |scrolling box|.
    1. If <var>position</var> is not the same as <var>scrolling box</var>'s current scroll position, or <var>scrolling box</var> has an ongoing <a>smooth scroll</a>,
        1. <dl class=switch>
                <dt>If <var>scrolling box</var> is associated with an element
                <dd>
                    <a for="/">Perform a scroll</a> of the element's <var>scrolling box</var> to <var>position</var>, with the element as the associated element and
                    <var>behavior</var> as the scroll behavior.
                    Add the {{Promise}} retured from this step to the set <var>ancestorPromises</var>.
                <dt>If <var>scrolling box</var> is associated with a <a>viewport</a>
                <dd>
                    1. Let <var>document</var> be the <a>viewport’s</a> associated {{Document}}.
                    1. Let <var>root element</var> be <var>document</var>'s [=root element=], if there is one, or null otherwise.
                    1. <a for="viewport">Perform a scroll</a> of the <a>viewport</a> to <var>position</var>, with <var>root element</var> as the associated element and <var>behavior</var>
                        as the scroll behavior.
                        Add the {{Promise}} retured from this step in the set <var>ancestorPromises</var>.
            </dl>
    1. If <var>container</var> is not null and either <var>scrolling box</var>
        is a [=shadow-including inclusive ancestor=] of <var>container</var> or
        is a <a>viewport</a> whose <a for="/">document</a> is a [=shadow-including inclusive ancestor=] of <var>container</var>,
        abort any remaining iteration of this loop.
1. Let <var>scrollPromise</var> be a new {{Promise}}.
1. Return <var>scrollPromise</var>, and run the remaining steps <a>in parallel</a>.
1. Resolve <var>scrollPromise</var> when all {{Promise}}s in <var>ancestorPromises</var> have settled.

</div>

<div algorithm>

To <dfn>scroll an element</dfn> (or [=pseudo-element=]) <var>element</var> to <var>x</var>,<var>y</var> optionally with a scroll behavior <var>behavior</var> (which is "<code>auto</code>" if omitted) means to:

1. Let <var>box</var> be <var>element</var>'s associated <a>scrolling box</a>.
1. <dl class=switch>
        <dt>If <var>box</var> has rightward <a>overflow direction</a>
        <dd>Let <var>x</var> be max(0, min(<var>x</var>, <var>element</var> <a>scrolling area</a> width - <var>element</var> <a>padding edge</a> width)).

        <dt>If <var>box</var> has leftward <a>overflow direction</a>
        <dd>Let <var>x</var> be min(0, max(<var>x</var>, <var>element</var> <a>padding edge</a> width - <var>element</var> <a>scrolling area</a> width)).
    </dl>
1. <dl class=switch>
        <dt>If <var>box</var> has downward <a>overflow direction</a>
        <dd>Let <var>y</var> be max(0, min(<var>y</var>, <var>element</var> <a>scrolling area</a> height - <var>element</var> <a>padding edge</a> height)).

        <dt>If <var>box</var> has upward <a>overflow direction</a>
        <dd>Let <var>y</var> be min(0, max(<var>y</var>, <var>element</var> <a>padding edge</a> height - <var>element</var> <a>scrolling area</a> height)).
    </dl>
1. Let <var>position</var> be the scroll position <var>box</var> would have by aligning <a>scrolling area</a> x-coordinate <var>x</var> with the left of <var>box</var> and aligning <a>scrolling area</a> y-coordinate <var>y</var> with the top of <var>box</var>.
1. If <var>position</var> is the same as <var>box</var>'s current scroll position, and <var>box</var> does not have an ongoing <a>smooth scroll</a>, return a resolved {{Promise}} and abort the remaining steps.
1. <a for="/">Perform a scroll</a> of <var>box</var> to <var>position</var>, <var>element</var> as the associated element and <var>behavior</var> as the scroll behavior.
    Let <var>scrollPromise</var> be the {{Promise}} returned from this step.
1. Return <var>scrollPromise</var>.

</div>


<h2 id=extensions-to-the-htmlelement-interface>Extensions to the {{HTMLElement}} Interface</h2>

<pre class=idl>
partial interface HTMLElement {
  readonly attribute Element? scrollParent;
  readonly attribute Element? offsetParent;
  readonly attribute long offsetTop;
  readonly attribute long offsetLeft;
  readonly attribute long offsetWidth;
  readonly attribute long offsetHeight;
};
</pre>

The <dfn attribute for=HTMLElement>scrollParent</dfn> attribute must return the result of running these steps:
1. If any of the following holds true, return null and terminate this algorithm:
    * The element does not have an associated [=CSS/box=].
    * The element is the [=root element=].
    * The element is <a>the <code>body</code> element</a>.
    * The element's computed value of the 'position' property is ''position/fixed'' and no ancestor establishes a fixed position [=containing block=].
1. Let <var>ancestor</var> be the [=containing block=] of the element in the <a>flat tree</a> and repeat these substeps:
    1. If <var>ancestor</var> is the [=initial containing block=], return the {{Document/scrollingElement}} for the element's document if it is not <a>closed-shadow-hidden</a> from the element, otherwise return null.
    1. If <var>ancestor</var> is not <a>closed-shadow-hidden</a> from the element, and is a <a>scroll container</a>, terminate this algorithm and return <var>ancestor</var>.
    1. If the computed value of the 'position' property of <var>ancestor</var> is ''position/fixed'',  and no ancestor establishes a fixed position [=containing block=], terminate this algorithm and return null.
    1. Let <var>ancestor</var> be the [=containing block=] of <var>ancestor</var> in the <a>flat tree</a>.

<wpt>
    scrollParent-shadow-tree.html
    scrollParent.html
</wpt>

The <dfn attribute for=HTMLElement>offsetParent</dfn> attribute must return the result of running these steps:

1. If any of the following holds true return null and terminate this algorithm:
    * The element does not have an associated [=CSS/box=].
    * The element is the [=root element=].
    * The element is <a>the <code>body</code> element</a>.
    * The element's computed value of the 'position' property is ''position/fixed'' and no ancestor establishes a fixed position [=containing block=].
1. Let <var>ancestor</var> be the parent of the element in the <a>flat tree</a> and repeat these substeps:
    1. If <var>ancestor</var> is <a>closed-shadow-hidden</a> from the element, its computed value of the 'position' property is ''position/fixed'', and no ancestor establishes a fixed position [=containing block=], terminate this algorithm and return null.
    1. If <var>ancestor</var> is not <a>closed-shadow-hidden</a> from the element and satisfies at least one of the following, terminate this algorithm and return <var>ancestor</var>.
        * The element is in a fixed position [=containing block=], and <var>ancestor</var> is a containing block for fixed-positioned descendants.
        * The element is not in a fixed position [=containing block=], and:
            * <var>ancestor</var> is a containing block of absolutely-positioned descendants (regardless of whether there are any absolutely-positioned descendants).
            * It is <a>the <code>body</code> element</a>.
            * The computed value of the 'position' property of the element is ''static'' and the ancestor is one of the following <a>HTML elements</a>: <code>td</code>, <code>th</code>, or <code>table</code>.
        * The element has a different [=effective zoom=] than <var>ancestor</var>.
    1. If there is no more parent of <var>ancestor</var> in the <a>flat tree</a>, terminate this algorithm and return null.
    1. Let <var>ancestor</var> be the parent of <var>ancestor</var> in the <a>flat tree</a>.

<wpt>
    offsetParent_element_test.html
    offsetParent-block-in-inline.html
    offsetParent-fixed.html
</wpt>

The <dfn attribute for=HTMLElement>offsetTop</dfn> attribute must return the result of running these steps:

1. If the element is <a>the <code>body</code> element</a> or does not have any associated [=CSS/box=] return zero and terminate this algorithm.
1. If the {{HTMLElement/offsetParent}} of the element is null return the [=unscaled=] y-coordinate of the top <a>border edge</a> of the first [=CSS/box=] associated with the element, relative to the <a>initial containing block</a> origin, ignoring any <a>transforms</a>that apply to the element and its ancestors and terminate this algorithm.
1. Return the [=unscaled=] result of subtracting the y-coordinate of the top <a>padding edge</a>
    of the first [=CSS/box=] associated with the {{HTMLElement/offsetParent}} of the element
    from the y-coordinate of the top <a>border edge</a>
    of the first [=CSS/box=] associated with the element,
    relative to the <a>initial containing block</a> origin,
    ignoring any <a>transforms</a> that apply to the element and its ancestors.

    Note: An inline element that consists of multiple line boxes will only have its first [=CSS/box=] considered.

<wpt>
    offsetTop-offsetLeft-nested-offsetParents.html
    offsetTop-offsetLeft-with-zoom.html
    offsetTopLeft-border-box.html
    offsetTopLeft-empty-inline-offset.html
    offsetTopLeft-empty-inline.html
    offsetTopLeft-inline.html
    offsetTopLeft-leading-space-inline.html
    offsetTopLeft-table-caption.html
    offsetTopLeft-trailing-space-inline.html
    offsetTopLeftInScrollableParent.html
    table-offset-props.html
</wpt>

The <dfn attribute for=HTMLElement>offsetLeft</dfn> attribute must return the result of running these steps:

1. If the element is <a>the <code>body</code> element</a> or does not have any associated [=CSS/box=] return zero and terminate this algorithm.
1. If the {{HTMLElement/offsetParent}} of the element is null return the [=unscaled=] x-coordinate of the left <a>border edge</a> of the first [=CSS/box=] associated with the element, relative to the <a>initial containing block</a> origin, ignoring any <a>transforms</a> that apply to the element and its ancestors, and terminate this algorithm.
1. Return the [=unscaled=] result of subtracting the x-coordinate of the left <a>padding edge</a> of the first [=CSS/box=] associated with the {{HTMLElement/offsetParent}} of the element from the x-coordinate of the left <a>border edge</a> of the first [=CSS/box=] associated with the element, relative to the <a>initial containing block</a> origin, ignoring any <a>transforms</a> that apply to the element and its ancestors.

The <dfn attribute for=HTMLElement>offsetWidth</dfn> attribute must return the result of running these steps:

1. If the element does not have any associated [=CSS/box=] return zero and terminate this algorithm.
1. Return the [=unscaled=] width of the axis-aligned bounding box
    of the [=border boxes=]
    of all fragments generated by the element's [=principal box=],
    ignoring any <a>transforms</a> that apply to the element and its ancestors.

    If the element's [=principal box=] is an [=inline-level box=]
    which was "split" by a [=block-level=] descendant,
    also include fragments generated by the [=block-level=] descendants,
    unless they are zero width or height.

<wpt>
    htmlelement-offset-width-001.html
</wpt>

The <dfn attribute for=HTMLElement>offsetHeight</dfn> attribute must return the result of running these steps:

1. If the element does not have any associated [=CSS/box=] return zero and terminate this algorithm.
1. Return the [=unscaled=] height of the axis-aligned bounding box
    of the [=border boxes=]
    of all fragments generated by the element's [=principal box=],
    ignoring any <a>transforms</a> that apply to the element and its ancestors.

    If the element's [=principal box=] is an [=inline-level box=]
    which was "split" by a [=block-level=] descendant,
    also include fragments generated by the [=block-level=] descendants,
    unless they are zero width or height.


<h2 id=extensions-to-the-htmlimageelement-interface>Extensions to the {{HTMLImageElement}} Interface</h2>

<pre class=idl>
partial interface HTMLImageElement {
  readonly attribute long x;
  readonly attribute long y;
};
</pre>

The <dfn attribute for=HTMLImageElement>x</dfn> attribute, on getting, must return the [=scaled=] x-coordinate of the left <a>border edge</a> of the
first [=CSS/box=] associated with the element, relative to the <a>initial containing block</a> origin, ignoring any
<a>transforms</a> that apply to the element and its ancestors, or zero if there is no [=CSS/box=].

The <dfn attribute for=HTMLImageElement>y</dfn> attribute, on getting, must return the [=scaled=] y-coordinate of the top <a>border edge</a> of the
first [=CSS/box=] associated with the element, relative to the <a>initial containing block</a> origin, ignoring any
<a>transforms</a> that apply to the element and its ancestors, or zero if there is no [=CSS/box=].

<wpt>
    cssom-view-img-attributes-001.html
    image-x-y-zoom.html
    HTMLImageElement-x-and-y-ignore-transforms.html
</wpt>

<h2 id=extensions-to-the-range-interface>Extensions to the {{Range}} Interface</h2>

<pre class=idl>
partial interface Range {
  DOMRectList getClientRects();
  [NewObject] DOMRect getBoundingClientRect();
};
</pre>

The <dfn method for=Range>getClientRects()</dfn> method, when invoked, must return an empty
{{DOMRectList}} object if the range is not in the document and otherwise a {{DOMRectList}} object
containing a list of {{DOMRect}} objects in content order that matches the following constraints:

* For each element selected by the range, whose parent is not selected by the range, include the border areas returned by invoking {{Element/getClientRects()}} on the element.
* For each {{Text}} node selected or partially selected by the range (including when the
    boundary-points are identical), include [=scaled=] {{DOMRect}} object (for the part that is selected, not
    the whole line box). The bounds of these {{DOMRect}} objects are computed using font metrics;
    thus, for horizontal writing, the vertical dimension of each box is determined by the font
    ascent and descent, and the horizontal dimension by the text advance width. If the range covers
    a partial <a spec=css-text>typographic character unit</a> (e.g. half a surrogate pair or part of
    a grapheme cluster), the full <a spec=css-text>typographic character unit</a> must be included
    for the purpose of computing the bounds of the relevant {{DOMRect}}. [[!CSS-TEXT-3]] The
    <a>transforms</a> that apply to the ancestors are applied.

Note: The {{DOMRect}} objects returned by {{Range/getClientRects()}} are not <a spec=html>live</a>.

<wpt>
    range-bounding-client-rect-with-nested-text.html
    range-client-rects-surrogate-indexing.html
</wpt>

The <dfn method for=Range>getBoundingClientRect()</dfn> method, when invoked, must return the result of the following
algorithm:

1. Let <var>list</var> be the result of invoking {{Range/getClientRects()}} on the same range this method was invoked on.
1. If <var>list</var> is empty return a {{DOMRect}} object whose {{DOMRect/x}}, {{DOMRect/y}}, {{DOMRect/width}} and {{DOMRect/height}} members are zero.
1. If all rectangles in <var>list</var> have zero width or height, return the first rectangle in
    <var>list</var>.
1. Otherwise, return a {{DOMRect}} object describing the smallest rectangle that includes all
    of the rectangles in <var>list</var> of which the height or width is not zero.

Note: The {{DOMRect}} object returned by {{Range/getBoundingClientRect()}} is not <a spec=html>live</a>.

<wpt>
    range-bounding-client-rect-with-display-contents.html
</wpt>

<h2 id=extensions-to-the-mouseevent-interface>Extensions to the {{MouseEvent}} Interface</h2>

Issue: The object IDL fragment redefines some members. Can we resolve this somehow?

<!-- x/y do not match IE in the position:relative case but do match other
browsers -->

<pre class=idl>
partial interface MouseEvent {
  readonly attribute double screenX;
  readonly attribute double screenY;
  readonly attribute double pageX;
  readonly attribute double pageY;
  readonly attribute double clientX;
  readonly attribute double clientY;
  readonly attribute double x;
  readonly attribute double y;
  readonly attribute double offsetX;
  readonly attribute double offsetY;
};

partial dictionary MouseEventInit {
  double screenX = 0.0;
  double screenY = 0.0;
  double clientX = 0.0;
  double clientY = 0.0;
};
</pre>

<wpt>
    mouseEvent.html
</wpt>

The <dfn attribute for=MouseEvent>screenX</dfn> attribute must return the x-coordinate of
the position where the event occurred relative to the origin of the
<a>Web-exposed screen area</a>.

The <dfn attribute for=MouseEvent>screenY</dfn> attribute must return the y-coordinate of
the position where the event occurred relative to the origin of the
<a>Web-exposed screen area</a>.

The <dfn attribute for=MouseEvent>pageX</dfn> attribute must follow these steps:

1. If the event's <a>dispatch flag</a> is set, return the horizontal coordinate of the position where the event occurred relative to the origin of the <a>initial containing block</a> and terminate these steps.
1. Let <var>offset</var> be the value of the {{Window/scrollX}} attribute of the event's associated {{Window}} object, if there is one, or zero otherwise.
1. Return the sum of <var>offset</var> and the value of the event's {{MouseEvent/clientX}} attribute.

The <dfn attribute for=MouseEvent>pageY</dfn> attribute must follow these steps:

1. If the event's <a>dispatch flag</a> is set, return the vertical coordinate of the position where the event occurred relative to the origin of the <a>initial containing block</a> and terminate these steps.
1. Let <var>offset</var> be the value of the {{Window/scrollY}} attribute of the event's associated {{Window}} object, if there is one, or zero otherwise.
1. Return the sum of <var>offset</var> and the value of the event's {{MouseEvent/clientY}} attribute.

The <dfn attribute for=MouseEvent>clientX</dfn> attribute must return the x-coordinate of
the position where the event occurred relative to the origin of the
<a>viewport</a>.

The <dfn attribute for=MouseEvent>clientY</dfn> attribute must return the y-coordinate of
the position where the event occurred relative to the origin of the
<a>viewport</a>.

The <dfn attribute for=MouseEvent>x</dfn> attribute must return the value of {{MouseEvent/clientX}}.

The <dfn attribute for=MouseEvent>y</dfn> attribute must return the value of {{MouseEvent/clientY}}.

The <dfn attribute for=MouseEvent>offsetX</dfn> attribute must follow these steps:

1. If the event's <a>dispatch flag</a> is set, return the x-coordinate of the position where the event occurred relative to the origin of the <a>padding edge</a> of the target node, ignoring the <a>transforms</a> that apply to the element and its ancestors, and terminate these steps.
1. Return the value of the event's {{MouseEvent/pageX}} attribute.

<wpt>
    mouseEvent-offsetXY-svg.html
</wpt>

The <dfn attribute for=MouseEvent>offsetY</dfn> attribute must follow these steps:

1. If the event's <a>dispatch flag</a> is set, return the y-coordinate of the position where the event occurred relative to the origin of the <a>padding edge</a> of the target node, ignoring the <a>transforms</a> that apply to the element and its ancestors, and terminate these steps.
1. Return the value of the event's {{MouseEvent/pageY}} attribute.


<h2 id=geometry>Geometry</h2>

<h3 id="the-geometryutils-interface" class=atrisk>The {{GeometryUtils}} Interface</h3>

<pre class=idl>
enum CSSBoxType { "margin", "border", "padding", "content" };
dictionary BoxQuadOptions {
  CSSBoxType box = "border";
  GeometryNode relativeTo; // XXX default document (i.e. viewport)
};

dictionary ConvertCoordinateOptions {
  CSSBoxType fromBox = "border";
  CSSBoxType toBox = "border";
};

interface mixin GeometryUtils {
  sequence&lt;DOMQuad> getBoxQuads(optional BoxQuadOptions options = {});
  DOMQuad convertQuadFromNode(DOMQuadInit quad, GeometryNode from, optional ConvertCoordinateOptions options = {});
  DOMQuad convertRectFromNode(DOMRectReadOnly rect, GeometryNode from, optional ConvertCoordinateOptions options = {});
  DOMPoint convertPointFromNode(DOMPointInit point, GeometryNode from, optional ConvertCoordinateOptions options = {}); // XXX z,w turns into 0
};

Text includes GeometryUtils; // like Range
Element includes GeometryUtils;
CSSPseudoElement includes GeometryUtils;
Document includes GeometryUtils;

typedef (Text or Element or CSSPseudoElement or Document) GeometryNode;
</pre>

The <dfn method for=GeometryUtils lt="getBoxQuads(options)|getBoxQuads()">getBoxQuads(<var>options</var>)</dfn> method must run the following steps:

<ol>
 <li class=issue>
  DOM order

  p1 = top left even in RTL

  scale to 0 means divide by zero, return 0x0

  cross-frames not allowed, throw WrongDocumentError?

  points are flattened (3d transform), z=0. like getClientRect

  test block in inline

  pseudo-elements before/after are children of the element

  viewport boxes are all the same
</ol>

<wpt>
    cssom-getBoxQuads-001.html
    cssom-getBoxQuads-002.html
</wpt>

The <dfn method for=GeometryUtils lt="convertQuadFromNode(quad, from, options)|convertQuadFromNode(quad, from)">convertQuadFromNode(<var>quad</var>, <var>from</var>, <var>options</var>)</dfn> method
must run the following steps:

<ol>
 <li><p class=issue>...
</ol>

The <dfn method for=GeometryUtils lt="convertRectFromNode(rect, from, options)|convertRectFromNode(rect, from)">convertRectFromNode(<var>rect</var>, <var>from</var>, <var>options</var>)</dfn> method
must run the following steps:

<ol>
 <li><p class=issue>...
</ol>

The <dfn method for=GeometryUtils lt="convertPointFromNode(point, from, options)|convertPointFromNode(point, from)">convertPointFromNode(<var>point</var>, <var>from</var>, <var>options</var>)</dfn>
method must run the following steps:

<ol>
 <li><p class=issue>...
</ol>

<h2 id=visualViewport>VisualViewport</h2>

<h3 id="the-visualviewport-interface">The {{VisualViewport}} Interface</h3>

<pre class=idl>
[Exposed=Window]
interface VisualViewport : EventTarget {
  readonly attribute double offsetLeft;
  readonly attribute double offsetTop;

  readonly attribute double pageLeft;
  readonly attribute double pageTop;

  readonly attribute double width;
  readonly attribute double height;

  readonly attribute double scale;

  attribute EventHandler onresize;
  attribute EventHandler onscroll;
  attribute EventHandler onscrollend;
};
</pre>

The <dfn attribute for=VisualViewport>offsetLeft</dfn> attribute must run these steps:
1. If the <a>visual viewport</a>'s <a for=visualviewport>associated document</a> is not <a>fully active</a>, return 0.
1. Otherwise, return the offset of the left edge of the <a>visual viewport</a> from the left edge
    of the <a>layout viewport</a>.

The <dfn attribute for=VisualViewport>offsetTop</dfn> attribute must run these steps:
1. If the <a>visual viewport</a>'s <a for=visualviewport>associated document</a> is not <a>fully active</a>, return 0.
1. Otherwise, return the offset of the top edge of the <a>visual viewport</a> from the top edge
    of the <a>layout viewport</a>.

The <dfn attribute for=VisualViewport>pageLeft</dfn> attribute must run these steps:
1. If the <a>visual viewport</a>'s <a for=visualviewport>associated document</a> is not <a>fully active</a>, return 0.
1. Otherwise, return the offset of the left edge of the <a>visual viewport</a> from the left edge
    of the <a>initial containing block</a> of the <a>layout viewport</a>'s <a for="/">document</a>.

The <dfn attribute for=VisualViewport>pageTop</dfn> attribute must run these steps:
1. If the <a>visual viewport</a>'s <a for=visualviewport>associated document</a> is not <a>fully active</a>, return 0.
1. Otherwise, return the offset of the top edge of the <a>visual viewport</a> from the top edge
    of the <a>initial containing block</a> of the <a>layout viewport</a>'s <a for="/">document</a>.

The <dfn attribute for=VisualViewport>width</dfn> attribute must run these steps:
1. If the <a>visual viewport</a>'s <a for=visualviewport>associated document</a> is not <a>fully active</a>, return 0.
1. Otherwise, return the width of the <a>visual viewport</a> excluding the width of any rendered vertical <a>classic
    scrollbar</a> that is fixed to the visual viewport.

Note: Since this value is returned in CSS pixels, the value will decrease in magnitude if either <a>page zoom</a> or the
<a>scale factor</a> is increased.

Note: A scrollbar that is fixed to the visual viewport is one that does not change size or location as the visual
viewport is zoomed and panned. Because this value is in CSS pixels, when excluding the scrollbar width the UA must
account for how large the scrollbar is as measured in CSS pixels. That is, the amount excluded decreases when zooming in
and increases when zooming out.

The <dfn attribute for=VisualViewport>height</dfn> attribute must run these steps:
1. If the <a>visual viewport</a>'s <a for=visualviewport>associated document</a> is not <a>fully active</a>, return 0.
1. Otherwise, return the height of the <a>visual viewport</a> excluding the height of any rendered horizontal <a>classic
    scrollbar</a> that is fixed to the visual viewport.

The <dfn attribute for=VisualViewport>scale</dfn> attribute must run these steps:
1. If the <a>visual viewport</a>'s <a for=visualviewport>associated document</a> is not <a>fully active</a>, return 0
    and abort these steps.
1. If there is no output device, return 1 and abort these steps.
1. Otherwise, return the <a>visual viewport</a>'s <a>scale factor</a>.

<dfn attribute for=VisualViewport>onresize</dfn> is the <a>event handler IDL attribute</a> for the <a event>resize</a> event.

<dfn attribute for=VisualViewport>onscroll</dfn> is the <a>event handler IDL attribute</a> for the <a event>scroll</a> event.

<dfn attribute for=VisualViewport>onscrollend</dfn> is the <a>event handler IDL attribute</a> for the <a event>scrollend</a> event.

<h2 id=events>Events</h2>

<h3 id=resizing-viewports>Resizing viewports</h3>

This section integrates with the <a for=/>event loop</a> defined in HTML. [[!HTML]]

When asked to <dfn export for=Document>run the resize steps</dfn> for a {{Document}} <var>doc</var>, run these steps:

1. If <var>doc</var>'s <a>viewport</a> has had its width or height changed
    (e.g. as a result of the user resizing the browser window,
    or changing <span>page zoom</span>,
    or an <code>iframe</code> element's dimensions are changed)
    since the last time these steps were run,
    <a>fire an event</a> named <a event>resize</a>
    at the {{Window}} object associated with <var>doc</var>.
1. If the {{VisualViewport}} associated with <var>doc</var> has had its <a attribute for=VisualViewport>scale</a>,
    <a attribute for=VisualViewport>width</a>, or <a attribute for=VisualViewport>height</a> properties changed since
    the last time these steps were run, <a>fire an event</a> named <a event>resize</a> at the {{VisualViewport}}.

<wpt>
    resize-event-on-initial-layout-001.html
    resize-event-on-initial-layout-002.html
</wpt>

<h3 id=scrolling-events>Scrolling</h3>

This section integrates with the <a for=/>event loop</a> defined in HTML. [[!HTML]]

Each {{Document}} has an associated list of <dfn for=Document>pending scroll events</dfn>, which stores pairs of ({{EventTarget}}, {{DOMString}}), initially empty.

Whenever a <a>viewport</a> gets scrolled (whether in response to user interaction or by an API), the user agent must run these steps:

1. Let <var>doc</var> be the <a>viewport’s</a> associated {{Document}}.
1. If <var>doc</var> is a <a spec=css-scroll-snap lt="scroll snap container">snap container</a>,
    run the steps to <a spec=css-scroll-snap-2 lt="update scrollsnapchanging targets">update scrollsnapchanging targets</a>
    for <var>doc</var> with <var>doc</var>'s <a spec="css-scroll-snap-2">eventual snap target</a> in the block axis
    as newBlockTarget and <var>doc</var>'s <a spec="css-scroll-snap-2">eventual snap target</a> in the inline axis
    as newInlineTarget.
1. If (<var>doc</var>, <code>"scroll"</code>) is already in <var>doc</var>'s <a>pending scroll events</a>, abort these steps.
1. Append (<var>doc</var>, <code>"scroll"</code>) to <var>doc</var>'s <a>pending scroll events</a>.

Whenever an element gets scrolled (whether in response to user interaction or by an API), the user agent must run these steps:

1. Let <var>doc</var> be the element's <a>node document</a>.
1. If the element is a <a spec=css-scroll-snap lt="scroll snap container">snap container</a>,
    run the steps to <a spec=css-scroll-snap-2 lt="update scrollsnapchanging targets">update scrollsnapchanging targets</a>
    for the element with the element's <a spec="css-scroll-snap-2">eventual snap target</a> in the block axis
    as newBlockTarget and the element's <a spec="css-scroll-snap-2">eventual snap target</a> in the inline axis
    as newInlineTarget.
1. If the element is already in <var>doc</var>'s <a>pending scroll events</a>, abort these steps.
1. Append the element to <var>doc</var>'s <a>pending scroll events</a>.

Whenever a <a>visual viewport</a> gets scrolled (whether in response to user interaction or by an API), the user agent must run these steps:

1. Let <var>vv</var> be the {{VisualViewport}} object that was scrolled.
1. Let <var>doc</var> be <var>vv</var>'s <a for=visualviewport>associated document</a>.
1. If (<var>vv</var>, <code>"scroll"</code>) is already in <var>doc</var>'s <a>pending scroll events</a>, abort these steps.
1. Append (<var>vv</var>, <code>"scroll"</code>) to <var>doc</var>'s <a>pending scroll events</a>.

When asked to <dfn export for=Document>run the scroll steps</dfn> for a {{Document}} <var>doc</var>, run these steps:

Issue: In what order are scrollend events dispatched? Ordered based on scroll start or scroll completion?

1. For each scrolling box <var>box</var> that was scrolled:
    1. If <var>box</var> belongs to a <a>viewport</a>, let <var>doc</var> be the <a>viewport’s</a> associated {{Document}} and <var>target</var> be the <a>viewport</a>.
        If <var>box</var> belongs to a {{VisualViewport}}, let <var>doc</var> be the {{VisualViewport}}'s <a for=visualviewport>associated document</a> and <var>target</var>
        be the {{VisualViewport}}. Otherwise, <var>box</var> belongs to an element and let <var>doc</var> be the element's <a>node document</a> and <var>target</var> be the element.
    1. If <var>box</var> belongs to a <a spec=css-scroll-snap lt="scroll snap container">snap container</a>, |snapcontainer|,
        run the <a spec=css-scroll-snap-2 lt="update scrollsnapchange targets">update scrollsnapchange targets</a> steps for |snapcontainer|.
    1. If (<var>target</var>, <code>"scrollend"</code>) is already in <var>doc</var>'s <a>pending scroll events</a>, abort these steps.
    1. Append (<var>target</var>, <code>"scrollend"</code>) to <var>doc</var>'s <a>pending scroll events</a>.

1. For each item (<var>target</var>, <var>type</var>) in <var>doc</var>'s <a>pending scroll events</a>,
    in the order they were added to the list, run these substeps:

    1. If <var>target</var> is a {{Document}}, and <var>type</var> is <code>"scroll"</code> or <code>"scrollend"</code>,
        <a>fire an event</a> named <var>type</var> that bubbles at <var>target</var>.
    1. Otherwise, if <var>type</var> is <code>"scrollsnapchange"</code>, then:
      1. Let |blockTarget| and |inlineTarget| be null initially.
      1. If the <a>scrollsnapchangeTargetBlock</a> associated with <var>target</var> is a pseudo-element,
        set |blockTarget| to the owning element of that <a>scrollsnapchangeTargetBlock</a>.
      1. Otherwise, set |blockTarget| to that <a>scrollsnapchangeTargetBlock</a>.
      1. If the <a>scrollsnapchangeTargetInline</a> associated with <var>target</var> is a pseudo-element,
        set |inlineTarget| to the owning element of that <a>scrollsnapchangeTargetInline</a>.
      1. Otherwise, Set |inlineTarget| to that <a>scrollsnapchangeTargetInline</a>.
      1. Fire a {{SnapEvent}}, |snapevent|, named {{scrollsnapchange}} at <var>target</var>
        and let |snapevent|'s {{SnapEvent/snapTargetBlock}} and
        {{SnapEvent/snapTargetInline}} attributes be |blockTarget| and |inlineTarget| respectively.
    1. Otherwise, if <var>type</var> is <code>"scrollsnapchanging"</code>, then:
      1. Let |blockTarget| and |inlineTarget| be null initially.
      1. If the <a>scrollsnapchanging block-axis target</a> associated with <var>target</var> is a pseudo-element,
        set |blockTarget| to the owning element of that <a>scrollsnapchanging block-axis target</a>.
      1. Otherwise, set |blockTarget| to that <a>scrollsnapchanging block-axis target</a>.
      1. If the <a>scrollsnapchanging inline-axis target</a> associated with <var>target</var> is a pseudo-element,
        set |inlineTarget| to the owning element of that <a>scrollsnapchanging inline-axis target</a>.
      1. Otherwise, set |inlineTarget| to that <a>scrollsnapchanging inline-axis target</a>.
      1. Fire a {{SnapEvent}}, |snapevent|, named {{scrollsnapchanging}} at <var>target</var>
        and let |snapevent|'s {{SnapEvent/snapTargetBlock}} and
        {{SnapEvent/snapTargetInline}} attributes be |blockTarget| and |inlineTarget|, respectively.
    1. Otherwise, <a>fire an event</a> named <var>type</var> at <var>target</var>.
1. Empty <var>doc</var>'s <a>pending scroll events</a>.

Whenever scrolling is <a lt="scroll completed">completed</a>, the user agent must run these steps:

<h3 id=event-summary>Event summary</h3>

<i>This section is non-normative.</i>

<table class="complex data">
 <thead>
  <tr>
   <th>Event
   <th>Interface
   <th>Interesting targets
   <th>Description
 <tbody>
  <tr>
   <td><dfn event for="Window, VisualViewport">resize</dfn>
   <td>{{Event}}
   <td>{{Window}}, {{VisualViewport}}
   <td>Fired at the {{Window}} when the <a>viewport</a> is resized. Fired at {{VisualViewport}} when the <a>visual viewport</a> is resized
       or the <a>layout viewport</a> is scaled.
  <tr>
   <td><dfn event for="Document, Element, VisualViewport">scroll</dfn>
   <td>{{Event}}
   <td>{{VisualViewport}}, {{Document}}, elements
   <td>Fired at the {{VisualViewport}}, {{Document}} or element when the {{VisualViewport}}, <a>viewport</a>, or element is scrolled, respectively.
  <tr>
   <td><dfn event for="Document, Element, VisualViewport">scrollend</dfn>
   <td>{{Event}}
   <td>{{Document}}, elements, {{VisualViewport}}
   <td>Fired at the {{VisualViewport}}, {{Document}}, or element when a scroll is <a lt="scroll completed">completed</a>: the
      {{VisualViewport}}, <a>viewport</a>, or element has been scrolled, the scroll sequence has ended and any scroll offset changes have
      been applied.
</table>


Post-Layout State Snapshotting {#post-layout-snapshot}
======================================================

Some CSS features use post-layout state, like scroll position, as input to the next style and layout update.

When asked to <dfn export>run snapshot post-layout state steps</dfn> for a {{Document}} <var>doc</var>, run these steps:

1. For each CSS feature that needs to snapshot post-layout state, take a snapshot of the relevant state in <var>doc</var>.

The state that is snapshot is defined in other specifications. These steps must not invalidate <var>doc</var> or any other {{Document}}s in such a way that other post-layout snapshotting steps can observe that such snapshotting happened. It follows that the order of which such snapshotting takes place must not matter.


Privacy Considerations {#privacy}
===============================================

The {{Screen}} interface exposes information about the user's display configuration, which maybe be used as input to fingerprinting algorithms. User agents may choose to hide or quantize information about the screen size or configuration, in order to protect the user’s privacy.

{{MouseEvent}} contains information about the screen-relative coordinates of the event. User agents may set these properties to values that obscure the actual screen-relative location of the event, in order to protect the user’s privacy.

Security Considerations {#security}
===================================

No new security considerations have been reported on this specification.



Changes {#changes}
==================================================

This section documents some of the changes between publications of this specification. This section is not exhaustive. Bug fixes and editorial changes are
generally not listed.

<h3 id=changes-2016-03-17 class=no-num>
Changes since the <a href="https://www.w3.org/TR/2016/WD-cssom-view-1-20160317/">17 March 2016 Working Draft</a></h3>

* Added Simon Fraser and Emilio Cobos Álvarez as current editors and moved Simon Pieters to former editors.
* Clarified how {{Range/getClientRects()}} handles <a spec=css-text>typographic character unit</a>s.
* Changed how {{Element/getBoundingClientRect()}} of {{Element}} and {{Range/getBoundingClientRect()}} of {{Range}} handle empty rectangles.
* Changed definition of {{HTMLElement/offsetParent}} for Shadow DOM.
* Allowed UAs to lie about {{Screen}} properties for privacy reasons.
* Changed {{Screen/colorDepth}} and {{Screen/pixelDepth}} to return real values.
* Changed 'CSS pixels' to refer to [[!CSS-VALUES]].
* Changed default values for {{ScrollIntoViewOptions}} to <code>start</code> and <code>nearest</code> and slightly changed behavior of {{Element/scrollIntoView()}}
* Added {{Window/screenLeft}} and {{Window/screenTop}} as aliases for {{Window/screenX}} and {{Window/screenY}}.
* Defined overflow directions in terms of <a>block-end</a> and <a>inline-end</a>.
* Renamed the arguments to {{Window/resizeTo()}} to be <var>width</var> and <var>height</var>
* Added script-triggered scroll-snap to list of scrolls affected by 'scroll-behavior'.
* Fixed a logical error in the Terminology section.
* Added the "Security Considerations" and "Privacy Considerations" sections
* Moved the 'scroll-behavior' property to [[CSS-OVERFLOW-3]]
* Adjusted the algorithm for {{HTMLElement/offsetWidth}} and {{HTMLElement/offsetHeight}}.
* Added {{Element/checkVisibility()}} method to {{Element}}.
* Moved the <a event>scrollend</a> event from <a href="https://wicg.github.io/overscroll-scrollend-events/">WICG overscroll-scrollend-events</a> to [[CSSOM-VIEW-1]] and added details for handling them.
* Added a "get the bounding box" algorithm to {{Element/getBoundingClientRect()}}.
* Introduced the {{VisualViewport}} API and related concepts.
* Extended scroll into view algorithm to also work on {{Range|Ranges}}.
* Clarified whether scaled or unscaled dimensions are returned by various APIs in relation to the 'zoom' property.
* Took scroll snapping and scroll target into account for various scrolling APIs.
* Added {{Element/currentCSSZoom}} attribute to {{Element}}.
* Added options parameter to {{Document/caretPositionFromPoint()}} method.
* Removed caret range concept from CaretPosition interface.
* Defined post-layout snapshotting.
* Made the various scrolling algorithms accept a pseudo-element.
* Added ''container'' option to {{ScrollIntoViewOptions}}.
* Added the {{HTMLElement/scrollParent}} attribute.
* Pinch zoom got renamed to <a>scale factor</a>.

<h3 id=changes-2013-12-17 class=no-num>
Changes since the <a href="https://www.w3.org/TR/2013/WD-cssom-view-20131217/">17 December 2013 Working Draft</a></h3>

* The {{Element/scrollIntoView()}} method on {{Element}} was changed and extended.
* The {{Element/scrollTop}} and {{Element/scrollLeft}} IDL attributes on {{Element}} changed to no
    longer take an object; the {{Element/scroll()}}, {{Element/scrollTo()}} and
    {{Element/scrollBy()}} methods were added instead.
* The {{Element/scrollWidth}}, {{Element/scrollHeight}}, {{Element/clientTop}},
    {{Element/clientLeft}}, {{Element/clientWidth}} and {{Element/clientHeight}} IDL attributes on
    {{Element}} were changed back to return integers.
* The <code>DOMRectList</code> interface was removed.
* The {{Document/scrollingElement}} IDL attribute on {{Document}} was added.
* Some readonly attributes on {{Window}} were annotated with <code>[Replaceable]</code> IDL extended
    attribute.
* {{MediaQueryList}}, <a event>scroll</a> event and <a event>resize</a> event are integrated with
    the <a for=/>event loop</a> in HTML so they are synchronized with animation frames.
* The <code>instant</code> value of 'scroll-behavior' was renamed to ''scroll-behavior/auto''.
* The origin of {{Element/scrollLeft}} on {{Element}} was changed (for RTL).
* The {{Element/scrollIntoView()}} method on {{Element}} and {{Window/scroll()}},
    {{Window/scrollTo()}} and {{Window/scrollBy()}} methods on {{Window}} take the relevant
    dictionary as the first argument.
* The {{MediaQueryList}} interface was changed to use regular event API and define
    {{MediaQueryList/addListener()}} in terms of that.
* Added "Change History" section.
* Moved Glenn Adams to former editors.

<h3 id=changes-2011-08-04 class=no-num>
Changes since the <a href="https://www.w3.org/TR/2011/WD-cssom-view-20110804/">04 August 2011 Working Draft</a></h3>

* Added Simon Pieters and Glenn Adams as editors and moved Anne van Kesteren to former editors.
* Introduced 'scroll-behavior' CSS property.
* Added <a>Block flow direction</a> and <a>inline base direction</a> from [[CSS-WRITING-MODES-3]] to terminology.
* Added section about zooming.
* Added {{Window/moveTo()}}, {{Window/moveBy()}}, {{Window/resizeTo()}}, and {{Window/resizeBy()}} methods to {{Window}}.
* Added {{Window/devicePixelRatio}} attribute to {{Window}}.
* Introduced {{ScrollOptions}} dictionary and added an 'options' parameter to scrolling methods.
* Added {{Window/devicePixelRatio}} attribute to {{Window}}.
* Added ''features'' parameter to {{Window/open()}} method.
* Added {{Document/elementsFromPoint()}} method to {{Document}}.
* Added {{CaretPosition/getClientRect()}} method to {{CaretPosition}}.
* Introduced initial draft of {{GeometryUtils}} interface.
* Changed {{Window/innerWidth}}, {{Window/innerHeight}}, etc. to use ''double''.
* CSS <a>transforms</a> are now acknowledged.
* Replaced <code>ClientRect</code> by {{DOMRect}}.
* Defined the firing behavior of <a event>scroll</a> and <a event>resize</a> events.
* Changed {{Screen/colorDepth}} and {{Screen/pixelDepth}} to always return 24.

<h3 id=changes-2009-08-04 class=no-num>
Changes since the <a href="https://www.w3.org/TR/2009/WD-cssom-view-20090804/">04 August 2009 Working Draft</a></h3>

* Removed redundant definition of terminology of other specifications, explicitly defining units (e.g. CSS pixels) and content/document content distinction.
* Introduced {{MediaQueryList}} interface.
* Moved the <code>matchMedium()</code> method of the <code>Media</code> to the {{Window}} interface, renamed it to {{Window/matchMedia()}}, and changed its return type to {{MediaQueryList}}.
* Removed the <code>AbstractView</code> and <code>Media</code> interfaces.
* Removed the <code>DocumentView</code> interface and moved methods {{Document/elementFromPoint()}} and <code>caretRangeFromPoint()</code> to the {{Document}} interface.
* Renamed the <code>caretRangeFromPoint()</code> method to {{Document/caretPositionFromPoint()}}.
* Introduced {{CaretPosition}} interface and changed the return type of {{Document/caretPositionFromPoint()}} to ''CaretPosition''.
* Added the {{Element/scrollIntoView()}} method to the {{Element}} interface.

<h3 id=changes-2008-02-22 class=no-num>
Changes since the <a href="https://www.w3.org/TR/2008/WD-cssom-view-20080222/">22 February 2008 Working Draft</a></h3>

* Removed the <code>WindowView</code> interface and moved its attributes and methods to an <code>AbstractView</code> and inheriting <code>ScreenView</code> interface.
* Added the <code>document</code> IDL attribute to <code>AbstractView</code>.
* Added the {{Window/scroll()}}, {{Window/scrollTo()}}, and {{Window/scrollBy()}} methods to the <code>ScreenView</code> interface.
* Removed the <code>ElementView</code> interface and moved its attributes and methods to the {{Element}} and {{HTMLElement}} interfaces.
* Added the {{Document/defaultView}} IDL attribute and <code>caretRangeFromPoint()</code> method to the <code>DocumentView</code> interface.
* Removed <code>RangeView</code> interface and instead directly extended the {{Range}} interface.
* Removed the <code>MouseEventView</code> interface and instead directly extended the {{MouseEvent}} interface.
* Renamed the <code>TextRectangleList</code> interface to <code>ClientRectList</code> and turned the <code>item()</code> method into an indexed getter.
* Renamed the <code>TextRectangle</code> interface to <code>ClientRect</code> and added the <code>width</code> and <code>height</code> attributes.

Acknowledgements {#acks}
==================================================

The editors would like to thank
Alan Stearns,
Alexey Feldgendler,
Antonio Gomes,
Bj&ouml;rn H&ouml;hrmann,
Boris Zbarsky,
Chris Rebert,
Corey Farwell,
Dan Bates,
David Vest,
Elliott Sprehn,
Garrett Smith,
Henrik Andersson,
Hallvord R. M. Steen,
Kang-Hao Lu,
Koji Ishii,
Leif Arne Storset,
Luiz Agostini,
Maciej Stachowiak,
Michael Dyck,
Mike Wilson,
Morten Stenshorne,
Olli Pettay,
Pavel Curtis,
Peter-Paul Koch,
Rachel Kmetz,
Rick Byers,
Robert O'Callahan,
Sam Weinig,
Scott Johnson,
Sebastian Zartner,
Stewart Brodie,
Sylvain Galineau,
Tab Atkins,
Tarquin Wilton-Jones,
Thomas Moore,
Thomas Shinnick,
and
Xiaomei Ji
for their contributions to this document.

Special thanks to the Microsoft employees who first implemented many of
the features specified in this draft, which were first widely deployed by
the Windows Internet Explorer browser.

<wpt hidden title="Tests related to implementation bugs, not linked to specific normative text.">
    client-props-root-display-none-crash.html
    overflow-hidden-smooth-scroll-crash.html
</wpt>

<wpt hidden title="Tests for scroll-behavior, which moved to CSS Overflow Module Level 3">
    inheritance.html
    parsing/scroll-behavior-computed.html
    parsing/scroll-behavior-invalid.html
    parsing/scroll-behavior-valid.html
    position-sticky-root-scroller-with-scroll-behavior.html
    scroll-back-to-initial-position.html
    scroll-behavior-default-css.html
    scroll-behavior-element.html
    scroll-behavior-main-frame-root.html
    scroll-behavior-main-frame-window.html
    scroll-behavior-scrollintoview-nested.html
    scroll-behavior-smooth-navigation.html
    scroll-behavior-smooth-positions.html
    scroll-behavior-smooth.html
    scroll-behavior-subframe-root.html
    scroll-behavior-subframe-window.html
</wpt>
